과일 포장 공장


21

귀하의 임무는 컨베이어 벨트에서 포장재를 포장재로 포장하여 소매 업체로 발송하도록 최적화 할 수있는 알고리즘 (프로그램 또는 기능)을 구축하여 가장 많은 수의 포장재를 최적화하는 것입니다.

각각의 백은 적어도 특정 양의 중량을 가져야하지만, 그 중량이 다른 백을 채우기 위해 사용될 수 있기 때문에 초과분은 이익을 잃게된다. 포장 기계는 항상 n대기열에서 과일을 미리 보며 n처리되는 (단일) 가방에 과일을 추가하도록 선택할 수 있습니다 . n대기열 의 첫 번째 요소 이상을 볼 수 없습니다 . 프로그램은 항상 가방에 이미 얼마나 많은 무게가 있는지 정확히 알고 있습니다.

이를 시각화하는 또 다른 방법 n은 끝에 새로운 과일이 닿기 전에 과일을 가져와야 하는 적재 공간이있는 컨베이어 벨트를 갖는 것 입니다. 마지막에 남은 과일과 가득 찬 가방은 버립니다.

그림 1 : 과일 포장 공장

입력

  • 대기열에있는 과일 무게의 목록 / 배열 (정수)
  • 백의 최소 총 중량 (양의 정수)
  • Lookahead n(양의 정수)

산출

알고리즘은 모든 가방에 과일과 과일의 무게를 반환해야합니다. 컴퓨터에서 1 분 안에 프로그램을 실행하고 점수를 계산할 수 있어야합니다.

Total weight 1000, lookahead of 3 and fruit queue: 
[171,163,172,196,156,175,162,176,155,182,189,142,161,160,152,162,174,172,191,185]

One possible output (indented to show how the lookahead affects the bagging):
[171,163,172,    156,175,    176]
                        [162,    155,182,189,    161,160]
                                                        [152,162,174,172,191,185]

채점

귀하의 알고리즘은 내가 준비한 10000 개의 오렌지 배치 에서 6 번 실행 되며 양쪽 끝을 포함하여 2 ~ 7 범위의 미리보기에서 테스트 됩니다. 최소 1000 단위의 가방에 포장해야합니다. 오렌지는 일반적으로 평균 무게가 170이고 표준 편차가 13이면 분포됩니다.

당신의 점수는 6 번 달리기에서 나온 가방의 합계입니다. 가장 높은 점수가 이깁니다. 표준 허점은 허용되지 않습니다.

Haskell의 간단한 예제 구현 및 테스트 스위트 보일러 플레이트


7
사람들에게 와서, 아직도 아직 고르지 않은 과일 알고리즘이 아직 남아 있다고 생각합니다.
Angs

2
프로그램이 평균 무게 / 배포를 하드 코딩 할 수 있습니까? (이것은 비슷한 배치에서도 똑같이 잘 작동한다고 가정합니다. 물론 하드 코딩은 제한된 lookahead의 목적을 파괴하기 때문에 모든 것이 유효하지 않습니다)
user202729

@ user202729 : 그렇습니다.

그리고 모든 것을 하드 코딩하는 것은 어쨌든 금지 된 표준 허점 입니다.

룩 헤드가 무엇인지 알 수 없음
l4m2

답변:


8

파이썬 3, 9964 9981 봉지

이 솔루션의 아이디어는 Jonathan, JayCe 및 fortraan의 아이디어와 비슷하지만 점수 함수 =)

이 솔루션은에 맞는 lookahead 영역의 최상의 하위 집합을 추가합니다 score.

score 다음 체계를 사용하여 서브 세트보다 순서를 제공합니다.

  • 가방을 완성하는 부분 집합이 아닌 가방보다 낫다
  • 무게가 덜 나가면 가방을 완성하는 한 부분 집합이 다른 것보다 낫다
  • 가방을 완성하지 않은 한 부분 집합이 평균이 가방에있을 것으로 예상되는 경우 다른 것보다 낫다

expected_mean 나머지 값이 어떻게 보이는지 예측하려고합니다 (선택이 최적이라고 가정).

UPD :

또 다른 관찰 결과는 다음과 같습니다. 알고리즘 성능을 손상시키지 않으면 서 최상의 하위 집합의 오렌지를 백에 넣을 수 있습니다. 그것의 어떤 부분을 움직여도 나머지는 계속 움직일 수 있으며, 점수가 맞다면 나머지는 여전히 가장 좋은 옵션이 될 것입니다. 또한, 이러한 방식으로, 백을 채우기 전에 더 많은 오렌지를보고 백에 넣을 후보 세트를 동적으로 개선 할 수 있습니다. 그리고 당신은 가능한 한 많은 정보를 알고 싶기 때문에, 주어진 시간에 하나 이상의 오렌지를 가방으로 옮기는 데 아무런 소용이 없습니다.

import itertools as it
import math
from functools import partial
from collections import Counter


mean, std = 170, 13


def powerset(list_, max_items):
    return it.chain.from_iterable(it.combinations(list_, r) for r in range(1, max_items + 1))


def expected_mean(w):
    spread = std * 1
    return max(mean - spread, min(mean + spread, w / max(1, round(w / mean))))


def score(weight_needed, candidate):
    c_sum = sum(candidate)
    c_mean = c_sum / len(candidate)
    if c_sum >= weight_needed:
        return int(-2e9) + c_sum - weight_needed
    return abs(expected_mean(weight_needed) - c_mean)


def f(oranges, min_bag_weight, lookahead):
    check = Counter(oranges)

    oranges = oranges.copy()
    result = []
    bag = []

    while oranges:
        weight_needed = min_bag_weight - sum(bag)

        lookahead_area = oranges[:lookahead]
        tail = oranges[lookahead:]

        to_add = min(powerset(lookahead_area, lookahead),
                     key=partial(score, weight_needed))
        to_add = min(powerset(to_add, 1),
                     key=partial(score, weight_needed))

        bag.extend(to_add)
        for x in to_add:
            lookahead_area.remove(x)
        oranges = lookahead_area + tail

        if sum(bag) >= min_bag_weight:
            result.append(bag)
            bag = []

    assert check == Counter(oranges) + Counter(bag) + sum(map(Counter, result), Counter())

    return result


if __name__ == '__main__':
    with open('oranges') as file:
        oranges = list(map(int, file))
    res = [f(oranges, 1000, l) for l in range(2, 7+1)]
    print(sum(map(len, res)))

시도 해봐!


아주 좋아요! 그것은 1672의 lookahead와 함께 1672를 얻습니다.

( powerset이 경우 함수에 대한 두 번째 인수 는 len(list_)어쨌든 같기 때문에 중복되는 것처럼 보 입니까?)
user202729

@user 이전 버전에서이 매개 변수를 실험했습니다. 아마 나중에 제거합니다
Alex

1
최고의 하위 집합에서 최고의 단일 요소의 강력한 조합을 발견하고 최고 점수를 얻은 것을 축하합니다! 현상금은 당신입니다.

expected_mean(w)좋은 결과를 제공 하는 간단한 :return (w+2) / max(1, round((w+2) / mean))
Angs

10

파이썬 3 , 9796 가방

Jonathan의 답변을 바탕으로 :

import itertools as it

def powerset(iterable):
    s = list(iterable)
    return it.chain.from_iterable(it.combinations(s, r) for r in range(len(s)+1))

def f(a,m,l):
 r=[];b=[]
 while a:
  c =  min(list(powerset(a[:l])),key=lambda w: abs(sum(b)+sum(w)-m))
  if sum(c)==0:
   c = a[:l]
  b+=[a.pop(a.index(min(c,key=lambda w: abs(sum(b)+w-m))))]
  if sum(b)>=m:r+=[b];b=[]
 return r

이것은 itertool의 요리 책에있는 전원에 의존합니다. 먼저 모든 서브 세트에 대한 목표 가중치와의 차이를 최소화하여 버퍼의 최적 서브 세트를 찾은 다음 동일한 기준에 따라이 서브 세트에서 요소를 선택합니다. 전체 버퍼에서 최적의 서브 세트를 선택하지 않으면


PPCG에 오신 것을 환영합니다!
Martin Ender

@MartinEnder 환영하는 공감에 감사합니다 Martin :)
JayCe

1
아, 나는 거기에 트릭을 놓쳤다 ... 나는 다른 대답으로 이것에 아무런 문제가 없다!
Jonathan Allan

1
@JonathanAllan 감사합니다 Jonathan Jonathan 모든 사과없이 당신에게 크레딧을 드리기 위해 답변을 줄였습니다. 이것은 정규 분포 (170,13) 분포라는 사실을 사용하여 개선 할 수 있습니다. 다음 번에 더 나은 결실을 맺을 확률을 사용할 수 있다고 확신합니다.
JayCe

@JayCe는 도박꾼의 실수에 매우 가깝게 들립니다.
qwr

6

C ++ 17, 9961.58 (임의의 종자에 대한 평균)

(C ++을 모른다면 설명을 아래로 스크롤하십시오)

#include<iostream>

#include<vector>
#include<random>

std::mt19937 engine(279); // random engine
// random distribution of the oranges
std::normal_distribution dist (170.,13.);

int constexpr N_NEW_ORANGES=7;

/** Input format: Current remaining weight of the bag (remain) and 
the weight of the oranges (weights)
Output: the index of the orange to be pick.
*/
struct pick_orange{
    std::vector<int>weights,sum_postfix;int remain;

    /// returns {min excess, mask}, (index) is the LSB
    std::pair<int,int> backtrack(int index, int remain) {
        if(sum_postfix[index]<remain)return {1e9,0};
        int min_excess=1e9, good_mask=0;
        for(int next=index;next<N_NEW_ORANGES;++next){
            if(weights[next]==remain){
                return {0, 1<<(next-index)};
            }else if(weights[next]>remain){
                if(weights[next]-remain<min_excess){
                    min_excess=weights[next]-remain;
                    good_mask=1<<(next-index);
                }
            }else{
                auto[excess,mask]=backtrack(next+1,remain-weights[next]);
                if(excess<min_excess){
                    min_excess=excess;
                    good_mask=(mask<<1|1)<<(next-index);
                }
            }
        }
        return {min_excess,good_mask};
    } 

    int ans;

    pick_orange(std::vector<int> weights_,int remain_)
        :weights(std::move(weights_)),remain(remain_){

        int old_size=weights.size();

        std::vector<int> count (N_NEW_ORANGES, 0);
        weights.resize(N_NEW_ORANGES, 0);

        sum_postfix.resize(N_NEW_ORANGES+1);
        sum_postfix.back()=0;

        for(int _=0; _<500; ++_){

            for(int i=old_size;i<N_NEW_ORANGES;++i)
                weights[i] = dist(engine);

            // prepare sum postfix
            for(int i=N_NEW_ORANGES;i-->0;)
                sum_postfix[i]=weights[i]+sum_postfix[i+1];

            // auto[excess,mask]=backtrack(0,remain);
            int mask = backtrack(0,remain).second;

            for(int i=0; 

                mask
                // i < N_NEW_ORANGES

                ; mask>>=1, ++i){

                // if(mask&1)std::cout<<'(';
                // std::cout<<weights[i];
                // if(mask&1)std::cout<<')';
                // std::cout<<' ';

                count[i]+=mask&1;
            }

            // std::cout<<"| "<<remain<<" | "<<excess<<'\n';

        }

        std::vector<double> count_balanced(old_size, -1);
        for(int i=0;i<old_size;++i){
            if(count_balanced[i]>-1)continue;
            int sum=0,amount=0;
            for(int j=i;j<old_size;++j)
                if(weights[j]==weights[i]){sum+=count[j];++amount;}

            double avg=sum;avg/=amount;
            for(int j=i;j<old_size;++j)
                if(weights[j]==weights[i])count_balanced[j]=avg;
        }

        ans=old_size-1;
        for(int i=ans;i-->0;)
            if(count_balanced[i]>count_balanced[ans])ans=i;
        // Fun fact: originally I wrote `<` for `>` here and wonder
        // why the number of bags is even less than that of the
        // randomized algorithm
    }

    operator int()const{return ans;}
};


#include<iostream>
#include<fstream>
#include<algorithm>

int main(){
    // read input from the file "data"
    std::ifstream data ("data");
    std::vector<int> weights;
    int weight;while(data>>weight)weights.push_back(weight);

    int constexpr BAG_SIZE=1000;
    int total_n_bag=0;
    for(int lookahead=2;lookahead<=7;++lookahead){
        auto weights1=weights;
        std::reverse(weights1.begin(),weights1.end());

        int remain=BAG_SIZE,n_bag=0;
        std::vector<int> w;
        for(int _=lookahead;_--;){
            w.push_back(weights1.back());
            weights1.pop_back();
        }
        while(!weights1.empty()){
            int index=pick_orange(w,remain);

            remain-=w[index];
            if(remain<=0){
                ++n_bag;remain=BAG_SIZE;

                if(n_bag%100==0)
                    std::cout<<n_bag<<" bags so far..."<<std::endl;
            }
            w[index]=weights1.back();weights1.pop_back();
        }

        while(!w.empty()){
            int index=pick_orange(w,remain);
            remain-=w[index];
            if(remain<=0){++n_bag;remain=BAG_SIZE;}
            w.erase(w.begin()+index);
        }

        std::cout<<"lookahead = "<<lookahead<<", "
            "n_bag = "<<n_bag<<'\n';
        total_n_bag += n_bag;
    }

    std::cout<<"total_n_bag = "<<total_n_bag<<'\n';
}

// 재미있는 사실은 : 원래 내가 쓴 <위해 >여기 경이
// 가방의 수는 더 적은의보다 왜
// 무작위 알고리즘

( <기본적으로 사용되는 경우 알고리즘 은 백 수 를 최소화 하려고 시도합니다 )

이 답변에서 영감을 얻었습니다 .

250 회 반복을위한 TIO 링크 : 온라인으로 사용해보십시오!


오렌지의 무게와 가방의 나머지 무게가 pick_orange주어지면 선택해야 할 오렌지의 인덱스를 반환 하는 함수를 정의합니다 (실제로는 함수처럼 보이며 구조체입니다) .vector<int> weightsint remain

연산:

반복 500시간이 {
발생 난수 가 될 때까지 (가짜) 오렌지 (평균 170 STDDEV 13 정규 분포) N_NEW_ORANGES=7오렌지
합이 최소이고,보다 작은 어떤 서브 세트 선택 remain(함수 backtrack않는)
로서 그 서브 세트 내의 모든 오렌지 표시 좋은
}

같은 무게의 오렌지가 (실제) 오렌지 중 양호한 것으로 표시되는 횟수를 평균하면 오렌지가
가장 좋은 오렌지를 반환합니다


프로그램에서 문제로부터 유추 할 수없는 3 개의 하드 코딩 된 상수가 있습니다.

  • 랜덤 시드 (중요하지 않음)
  • N_NEW_ORANGES(예측 길이). 이것을 증가 시키면 프로그램은 기하 급수적으로 기하 급수적으로 길어집니다
  • 반복 횟수. 이를 늘리면 프로그램이 선형 적으로 더 오래 실행됩니다.

승인. 씨앗을 최선의 답변을 제공하는 것으로 바꾸는 것은 테스트 사례에 최적화하는 것처럼 보이지만 점수로 10, 다른 씨앗의 평균을 취해야합니다. 런타임을 중단시키기 위해 반복 횟수가 적은 버전에 TIO 링크를 게시 할 수 있습니까?

마지막으로 새로운 gcc를 얻은 후에 컴파일해야했습니다. 임의의 씨앗이있는 50 회 실행에서 평균 9961.58을 얻었습니다. 여전히 인상적입니다. 그래도 궁금해졌습니다. 알고리즘은 기본적으로 모든 가방에서 다시 훈련됩니다. 기억할 수있는 최고의 값이 고정되어 있습니까?

@Angs 나는이 경우에 암기를 사용하여 도울 수있는 방법이 없다고 생각합니다. 어떤 생각?
user202729

내 OS는 gcc 5.4.0과 함께 제공되며에 문제가 invalid use of template-name ‘std::normal_distribution’있습니다. gcc 7.1.0에는 문제가 없습니다.

4

파이썬 2 , 9756 가방

오렌지색 굴러 가자 ...

def f(a,m,l):
 r=[];b=[]
 while a:
  b+=[a.pop(a.index(min(a[:l],key=lambda w:abs(sum(b)+w-m))))]
  if sum(b)>=m:r+=[b];b=[]
 return r

온라인으로 사용해보십시오!

항상 버퍼에서 과일을 선택하여 새 무게와 목표 무게의 절대 차이를 최소화하십시오.


4

파이썬 3, 9806 봉지

Jonathan과 JayCe의 답변을 바탕으로 :

import itertools as it

def powerset(iterable):
    s = list(iterable)
    return it.chain.from_iterable(it.combinations(s, r) for r in range(len(s)+1))

def f(a,m,l):
 r=[];b=[]
 while a:
  c =  min(list(powerset(list(reversed(sorted(a[:l]))))),key=lambda w: abs((sum(b)+sum(w))-m))
  if sum(c)==0:
   c = a[:l]
  b+=[a.pop(a.index(min(c,key=lambda w: abs((sum(b)+w)-m))))]
  if sum(b)>=m:r+=[b];b=[]
 return r

온라인으로 사용해보십시오!

작동 원리

가방에 900 단위가 있으며 99 과일과 101 과일의 2 가지 과일이 있다고 가정 해보십시오. 99 유닛 과일이 lookahead 목록의 시작 부분에 가까워지면 min101 대신 과일을 선택합니다.이 경우, 나머지 1 유닛을 충족시키기 위해 다른 과일이 필요합니다. 이 경우 더 높은 가치의 과일을 선호하도록 프로그램을 변경했습니다.

전원을 켜기 전에 미리보기 목록을 정렬 한 후 되 돌리면됩니다.


4

PHP, 9975 봉지

  • 가능하면 오렌지 5 개로 이동
  • 가방을 시작할 때 극단적 인 가치를 선택하면 나중에 균형을 잡습니다
  • 가능하면 즉시 가방을 채우십시오
  • 가방 무게를 추정 곡선에 가깝게 유지하십시오 (5bag의 경우 n * 200, 6bag의 경우 n * 167 등).

모든 제출물 중에서 가장 길지만 읽을 수 있어야합니다.

class Belt
{
    private $file;
    private $windowSize;
    private $buffer = [];

    public function __construct($filename, $windowSize) {
        $this->file = new \SplFileObject($filename);
        $this->windowSize = $windowSize;
        $this->loadBuffer();
    }

    public function reset($windowSize) {
        $this->file->seek(0);
        $this->windowSize = $windowSize;
        $this->buffer = [];
        $this->loadBuffer();
    }

    public function peekBuffer() {
        return $this->buffer;
    }

    public function pick($index) {
        if (!array_key_exists($index, $this->buffer)) {
            return null;
        }
        $value = $this->buffer[$index];
        unset($this->buffer[$index]);
        $this->buffer = \array_values($this->buffer);
        $this->loadBuffer();
        return $value;
    }

    private function loadBuffer() {
        for ($c = count($this->buffer); $c < $this->windowSize; $c++) {
            if ($this->file->eof()) {
                return;
            }
            $line = $this->file->fgets();
            if (false !== $line && "" !== $line) {
                $this->buffer[] = trim($line);
            }
        }
    }
}

class Packer
{

    const BAG_TARGET_WEIGHT = 1000;
    const MEAN_WEIGHT = 170;
    const MEAN_COUNT = 6; //ceil(self::BAG_WEIGHT/self::MEAN_WEIGHT);
    const MEAN_TARGET_WEIGHT = 167; //ceil(self::BAG_WEIGHT/self::MEAN_COUNT);

    public static function pack(Belt $belt, Picker $picker) {
        $bag = ["oranges" => [], "buffers" => []];
        $bags = [];
        while ($oranges = $belt->peekBuffer()) {

            $index = $picker->pick($oranges, \array_sum($bag["oranges"]));
            $orange = $belt->pick($index);
            $bag["oranges"][] = $orange;
            $bag["buffers"][] = $oranges;

            if (\array_sum($bag["oranges"]) >= self::BAG_TARGET_WEIGHT) {
                $bags[] = $bag;
                $bag = ["oranges" => [], "buffers" => []];
            }
        }
        return $bags;
    }
}

class Base
{
    public static function bestPermutation($elements, $weight = 0) {
        if (\array_sum($elements) < Packer::BAG_TARGET_WEIGHT - $weight) {
            return null;
        }
        $permute = function ($weight, $elements) use (&$permute) {
            if ($weight >= Packer::BAG_TARGET_WEIGHT) {
                return [];
            }
            $best = \PHP_INT_MAX;
            $bestElements = [];
            foreach ($elements as $key => $value) {
                $sum = $weight + $value;
                $els = [$value];
                if ($sum < Packer::BAG_TARGET_WEIGHT) {
                    $subSet = $elements;
                    unset($subSet[$key]);
                    $els = $permute($weight + $value, $subSet);
                    $els[] = $value;
                    $sum = $weight + \array_sum($els);
                }
                if ($sum >= Packer::BAG_TARGET_WEIGHT && $sum < $best) {
                    $best = $sum;
                    $bestElements = $els;
                }
            }
            return $bestElements;
        };
        $best = $permute($weight, $elements);

        return $best;
    }

    public function pickLightestOutOfHeavierThan($buffer, $targetWeight) {
        $b = -1;
        $bW = PHP_INT_MAX;
        foreach ($buffer as $key => $value) {
            if ($targetWeight <= $value && $value < $bW) {
                $b = $key;
                $bW = $value;
            }
        }
        return $b;
    }

    public function pickClosestTo($buffer, $targetWeight) {
        $b = -1;
        $bW = PHP_INT_MAX;
        foreach ($buffer as $key => $value) {
            $diff = \abs($targetWeight - $value);
            if ($diff < $bW) {
                $b = $key;
                $bW = $diff;
            }
        }
        return $b;
    }

    public function pickFurthestFrom($buffer, $targetWeight) {
        $b = -1;
        $bW = \PHP_INT_MIN;
        foreach ($buffer as $key => $value) {
            $diff = \abs($targetWeight - $value);
            if ($diff > $bW) {
                $b = $key;
                $bW = $diff;
            }
        }
        return $b;
    }

    public function findMax($buffer) {
        $i = -1;
        $m = 0;
        foreach ($buffer as $k => $v) {
            if ($v > $m) {
                $m = $v;
                $i = $k;
            }
        }
        return $i;
    }

    public function findMin($buffer) {
        $i = -1;
        $m = \PHP_INT_MAX;
        foreach ($buffer as $k => $v) {
            if ($v < $m) {
                $m = $v;
                $i = $k;
            }
        }
        return $i;
    }

    public function minimalOrangeCount($buffer, $weight) {
        $elementsToAdd = ceil((Packer::BAG_TARGET_WEIGHT - $weight) / Packer::MEAN_WEIGHT);
        $buffer = \array_merge($buffer,
            \array_fill(0, \floor($elementsToAdd / 2), Packer::MEAN_WEIGHT - 7),
            \array_fill(0, \floor($elementsToAdd / 2), Packer::MEAN_WEIGHT + 7),
            \array_fill(0, $elementsToAdd - \floor($elementsToAdd / 2) * 2, Packer::MEAN_WEIGHT)
        );
        \rsort($buffer);
        $orangeCount = 0;
        foreach ($buffer as $w) {
            $weight += $w;
            $orangeCount++;
            if ($weight >= Packer::BAG_TARGET_WEIGHT) {
                return $orangeCount;
            }
        }
        return $orangeCount + (Packer::BAG_TARGET_WEIGHT - $weight) / Packer::MEAN_WEIGHT;
    }
}


class Picker extends Base
{
    public function pick($buffer, $weight) {
        $weightNeeded = Packer::BAG_TARGET_WEIGHT - $weight;

        $minimalOrangeCount = $this->minimalOrangeCount($buffer, $weight);
        $orangeTargetWeight = ceil($weightNeeded / $minimalOrangeCount);

        if (0 === $weight) {
            $mean = \array_sum($buffer) / count($buffer);
            if ($mean > $orangeTargetWeight) {
                return $this->findMin($buffer);
            } elseif ($mean < $orangeTargetWeight) {
                return $this->findMax($buffer);
            }
            return $this->pickFurthestFrom($buffer, $orangeTargetWeight);
        }

        $i = $this->pickLightestOutOfHeavierThan($buffer, $weightNeeded);
        if (-1 !== $i) {
            return $i;
        }
        $i = $this->pickClosestTo($buffer, $orangeTargetWeight);
        return -1 !== $i ? $i : 0;
    }
}

$bagCount = 0;
$belt = new Belt(__DIR__ . "/oranges.txt", 0);
for ($l = 2; $l <= 7; $l++) {
    $belt->reset($l);
    $bags = Packer::pack($belt, new Picker());
    $bagCount += count($bags);
    printf("%d -> %d\n", $l, count($bags));
}
echo "Total: $bagCount\n";

2-> 1645 3-> 1657 4-> 1663 5-> 1667 6-> 1671 7-> 1672 총계 : 9975

시도 해봐


좋은! 놀랍게도 현재 아이템 수를 사용한다는 것입니다. 결국, 각각 120 개의 가중치를 갖는 3 개의 아이템 또는 각각 160 개의 가중치를 갖는 3 개의 아이템이 있는지는 중요하지 않다.

@Angs 아마도 가능합니다. 현재 아이템 수는 "이봐, 때로는 5 개의 아이템 백을 할 수있다"라는 아이디어에 대한 간단한 지름길로 나왔고 5 개의 아이템 백을 작동시키는 방법에 대해 설명했다. 자유 시간 개선 : 올로
mleko

3

파이썬 3, 9855 개 9928 9947 9956 9964 가방

Jonathan Allan의 시작 코드를 기반으로하지만 읽을 수는 없습니다.

아이디어 : 1000/170 = 5.88 이후, 우리는 1000/6에 가까운 과일을 선택하려고합니다 (매직 상수로 피들 링). 그러나 가방의 마지막 과일이 폐기물을 최소화 할 수 있다면 대신 사용합니다.

이 솔루션에는 추가 된 각 과일에 대한 백섬 대상이 있습니다. 아마 여기서 멈출 것이다. targets배열 을 찾기 위해 Nelder-Mead를 사용했습니다 .

[  165.79534144   343.58443287   522.58081597   680.76516204   845.93431713 1063.17204861]
def f(a, m, l, targets):
    bags = []
    bag = []
    bag_sum = 0
    while a:
        buffer = a[:l]
        finishers = tuple(filter(lambda w: bag_sum + w >= m, buffer))
        if finishers:
            next_fruits = [min(finishers)]

        else:
            ind = len(bag)
            next_fruits = [min(buffer, key=lambda w: abs(targets[ind]-bag_sum-w))]

        for next_fruit in next_fruits:
            bag.append(a.pop(a.index(next_fruit)))
            bag_sum += bag[-1]

        if sum(bag) >= m:
            bags.append(bag)
            bag = []  # Reset bag
            bag_sum = 0

    return bags

9956 봉투

from itertools import combinations

def f(a,m,l):
    bags = []
    bag = []
    while a:
        buffer = a[:l]
        next_fruit = None
        single_fruit = True

        finishers = [w for w in buffer if sum(bag) + w >= m ]
        if finishers: next_fruit = min(finishers)

        if not next_fruit:
            if len(buffer) >= 4 and sum(bag) < 600:
                next_fruits = min(combinations(buffer, 2), key=
                                  lambda ws: abs(2*169-sum(ws)))
                for fruit in next_fruits:
                    bag.append(a.pop(a.index(fruit)))

                single_fruit = False  # Skip adding single fruit

            else:
                next_fruit = min(buffer, key=lambda w: abs(171.5-w))

        if single_fruit:
            bag.append(a.pop(a.index(next_fruit)))

        if sum(bag)>=m:
            bags.append(bag)
            bag = []

    return bags


oranges = [int(x.strip()) for x in open("fruit.txt").readlines()]
bagLists = []
for lookahead in (2,3,4,5,6,7):
    bagLists.append(f(oranges[:], 1000, lookahead))


totalBagsOver1000 = sum(map(len, bagLists))
print('bags: ', (totalBagsOver1000))

9947 가방 이 프로그램은 특히 간단하다 :

def f(a,m,l):
    bags = []
    bag = []
    while a:
        buffer = a[:l]
        next_fruit = None

        finishers = [w for w in buffer if sum(bag) + w >= m ]
        if finishers: next_fruit = min(finishers)

        if not next_fruit:
            next_fruit = min(buffer, key=lambda w: abs(171.5-w))

        bag.append(a.pop(a.index(next_fruit)))

        if sum(bag)>=m:
            bags.append(bag)
            bag = []

    return bags

1
좋은! Btw, 폐기물을 최소화하기 위해 마지막 항목을 고르는 것만으로도 강력하고 9862 봉지를 제공합니다.

그것들을 어떻게 생각 해냈 targets습니까? 무작위 데이터에 대한 훈련?
Alex

1
@Alex I so so : Nelder-Mead 방법 (음수 백을 손실 함수로 사용)
qwr

2

루비 , 9967 가방

def pick a, n
  if a.sum < n
    #return a.max
    d = n % 170
    return a.min_by{|w|
      [(w - d).abs, (w - d - 170).abs].min
    }
  end
  
  subsets = (0..a.length).map do |i|
    a.combination(i).to_a
  end.flatten(1)
  
  subsets.select!{|s|s.sum >= n}
  least_overkill = subsets.min_by{|s|s.sum}
  #puts "best: #{least_overkill.sort}"
  return least_overkill.min
end

def run list, weight, n
  bags = 0
  in_bag = 0
  while list.size > 0
    x = pick(list[0...n], weight - in_bag)
    i = list.index(x)
    raise new Exeption("not a valid weight") if(!i || i >= n)
    list.delete_at i
    in_bag += x
    if in_bag >= weight
      #puts in_bag
      in_bag = 0
      bags += 1
    end
  end
  return bags
end

온라인으로 사용해보십시오!

백을 채우기에 충분한 무게가있는 경우 백을 채울 수있는 가장 밝은 부분을 찾아 해당 부분의 가장 밝은 주황색을 사용하십시오. 그렇지 않으면, 남은 무게를 170의 배수에 최대한 가깝게하십시오.


2

라켓 / 도표, 9880 봉지

가방에 추가 할 과일 조각을 결정하려면 추가 과일 조각과 함께 최적의 가방 무게와 가방 무게를 비교하십시오. 최적의 무게라면 사용하십시오. 과체중이라면 초과 량을 최소화하십시오. 저체중 인 경우 최적의 간격을 유지 한 후 초과 량을 최소화하십시오.

;; types

(define-struct bagger (fruit look tray bag bags)) ; fruit bagger

;; constants

(define MBW 1000) ; minimum bag weight
(define AFW 170) ; average piece-of-fruit weight
(define GAP (- MBW AFW)) ; targeted gap
(define FRUIT (file->list "fruit-supply.txt")) ; supplied fruit

;; utility functions

(define (weigh-it ls)
  (if (empty? ls)
      0
      (+ (car ls) (weigh-it (cdr ls)))))

(define (ref-to-car ls ref)
  (if (zero? ref)
      ls
      (let ((elem (list-ref ls ref)))
        (cons elem (remove elem ls)))))

;; predicates

(define (bag-empty? bgr) (empty? (bagger-bag bgr)))
(define (bag-full? bgr) (>= (weigh-it (bagger-bag bgr)) MBW))
(define (fruit-empty? bgr) (empty? (bagger-fruit bgr)))
(define (tray-empty? bgr) (empty? (bagger-tray bgr)))
(define (tray-full? bgr) (= (length (bagger-tray bgr)) (bagger-look bgr)))
(define (target-not-set? target value) (and (empty? target) (empty? value)))

;; pick best piece of fruit

(define (pf-rec tray bag i target value diff)
  (if (or (target-not-set? target value) (< diff value))
      (pick-fruit (cdr tray) bag (add1 i) i diff)
      (pick-fruit (cdr tray) bag (add1 i) target value)))

(define (pick-fruit tray bag i target value)
  (if (empty? tray)
      target
      (let ((weight (weigh-it (cons (car tray) bag))))
        (cond
          ((= weight MBW) i)
          ((> weight MBW) (pf-rec tray bag i target value (- weight MBW)))
          ((< weight MBW)
           (if (> weight GAP)
               (pf-rec tray bag i target value (- weight GAP))
               (pf-rec tray bag i target value (modulo (- MBW weight) AFW))))))))

;; load tray, bag, bags, etc.

(define (load-bag bgr)
  (let* ((tray (bagger-tray bgr))
         (bag (bagger-bag bgr))
         (weight (+ (weigh-it tray) (weigh-it bag))))
    (if (= weight MBW)
        (struct-copy bagger bgr
                     (tray empty)
                     (bag (append tray bag)))
        (let ((new-tray (ref-to-car tray (pick-fruit tray bag 0 empty empty))))
          (struct-copy bagger bgr
                       (tray (cdr new-tray))
                       (bag (cons (car new-tray) bag)))))))

(define (load-bags bgr)
  (struct-copy bagger bgr
               (bag empty)
               (bags (cons (bagger-bag bgr) (bagger-bags bgr)))))

(define (load-tray bgr)
  (struct-copy bagger bgr
               (fruit (cdr (bagger-fruit bgr)))
               (tray (cons (car (bagger-fruit bgr)) (bagger-tray bgr)))))

;; run the bagger factory

(define (run-bagger-aux bgr)
  (cond
    ((bag-full? bgr) (run-bagger-aux (load-bags bgr)))
    ((bag-empty? bgr)
     (cond
       ((tray-full? bgr) (run-bagger-aux (load-bag bgr)))
       ((tray-empty? bgr)
        (if (fruit-empty? bgr)
            (length (bagger-bags bgr))
            (run-bagger-aux (load-tray bgr))))
       (else
        (if (fruit-empty? bgr)
            (run-bagger-aux (load-bag bgr))
            (run-bagger-aux (load-tray bgr))))))
    (else
     (cond
       ((tray-full? bgr) (run-bagger-aux (load-bag bgr)))
       ((tray-empty? bgr)
        (if (fruit-empty? bgr)
            (run-bagger-aux (load-bags bgr))
            (run-bagger-aux (load-tray bgr))))
       (else
        (if (fruit-empty? bgr)
            (run-bagger-aux (load-bag bgr))
            (run-bagger-aux (load-tray bgr))))))))

(define (run-bagger fruit look)
  (run-bagger-aux (make-bagger fruit look empty empty empty)))

;; stackexchange problem run

(define (run-problem fruit looks)
  (if (empty? looks)
      0
      (+ (run-bagger fruit (car looks)) (run-problem fruit (cdr looks)))))

(run-problem FRUIT '(2 3 4 5 6 7)) ; result = 9880

1

하스켈 , 9777 봉지

이것은 나의 첫 번째 시도였습니다.

  • 가방을 욕심으로 가득 채웠습니다.
  • 가방에 넣지 못하면 모든 오렌지를 플러시하십시오.
options[]=[(0,([],[]))]
options(first:rest)=[option|(sum,(now,later))<-options rest,
 option<-[(sum+first,(first:now,later)),(sum,(now,first:later))]]
bags _[_]_=[]
bags(w_sum,w_bag)(w_kilo:w_iyts)w_view=
 let(w_take,w_remd)=splitAt(w_view)w_iyts;
     w_fill=filter((>=(w_kilo-w_sum)).fst)(options w_take)
 in if null w_fill then bags(w_sum+sum w_take,w_bag++w_take)(w_kilo:w_remd)w_view
    else let(_,(w_now,w_later))=minimum w_fill in
         (w_bag++w_now):bags(0,[])(w_kilo:w_later++w_remd)w_view
main=print.sum$map(length.bags(0,[])(1000:batch))[2..7]

온라인으로 사용해보십시오!


1

하스켈 , 9981 봉지

Angs조나단 앨런JayCefortraan알렉스로마 Czyborra codegolf 파이썬 생각 같은 주요 기차를 따라 몇 가지 추가 수학 순도 하스켈 다시 고리 화 수

  • 새로운 오렌지가 추가되기 전에 오직 하나의 오렌지 만 약탈됩니다.
  • 편견은 과일을 선호하는 것을 선호합니다 ( (<miss)==False<True)
  • 편견은 가장 가능성이 높은 정수 채우기에 가까운 과일을 선호합니다.
  • 해당 정수의
    (m-n)/sqrt(n)==(n+1-m)/sqrt(n+1) <==> n=sqrt(m^2-1/4)-1/2 경우 https://en.wikipedia.org/wiki/Sum_of_normally_distributed_random_variables

    https://m.wolframalpha.com/input/?i=plot+abs (1-x) * sqrt (1), abs (2-x) * sqrt (2), abs (3-x) * sqrt ( 3), abs (4-x) * sqrt (4)

불필요한 무의미한 양념

subsets[]=[[]];subsets(f:t)=[r|s<-subsets t,r<-[s,f:s]]
mean=uncurry(div).(id***max 1).(sum&&&length)
bags[]_ _=[];bags batch(miss:have)n=let
 goal=div miss$ceiling(sqrt((fromIntegral miss/170)^2+1/4)-1/2)
 best=minimumBy.comparing.(((<miss)&&&(abs.(goal-))).); desk=take n batch
 pick=best id.best(if sum desk<miss then mean else sum).filter(>[]).subsets$desk
 in if pick < miss then bags(delete pick batch)(miss-pick:pick:have)n
       else (pick:have):bags(delete pick batch)[miss+sum have]n
main=print$id&&&sum$map(length.bags batch[1000])[2..7]

온라인으로 사용해보십시오!

수확 오렌지의 9981 그물 꼭대기 다른 숫자 이득을 산출하지 않고 전에 동안 내 10k011 가방 부적합 오렌지를 잡아 포장 닫히지 않은 가방의 철회 에 의해 실격 user69850 의 인물 user202729조 왕OVS hencefore 자격 현상금에 갔다 알렉스

김미 바운티!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.