フルーツ袋詰め工場


21

あなたの使命は、コンベヤーベルトから袋に果物を詰めて小売業者に送ることを最適化し、最大数の袋を最適化できるアルゴリズム(プログラムまたは機能)を構築することです。

各バッグには少なくとも一定量の重量が必要ですが、その重量を使用して別のバッグを満たすことができるため、超過分は利益を失います。袋詰め機は常にnキューからの果物を先読みしnており、処理中の(単一の)袋にこれらの果物のいずれかを追加することのみを選択できます。nキューの最初の要素を超えて見ることはできません。プログラムは、バッグの中にすでにある重量を常に正確に知っています。

これを視覚化するもう1つの方法はn、新しい果物が到着する前に果物を採取する必要がある場所に、最終的なサイズの積載エリアを備えたコンベアベルトを用意することです。最後に残った果物と満杯でない袋は廃棄されます。

図1:果物の袋詰め工場

入力

  • キュー内の果物の重量のリスト/配列(正の整数)
  • バッグの最小総重量(正の整数)
  • 先読み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個のオレンジのバッチで、両端を含む2〜7の先読みで6回実行してテストされます。少なくとも1000ユニットの袋に詰めてください。オレンジは通常、平均重量170、標準偏差13で分布しています。

スコアは、6回の実行からのバッグの数の合計になります。最高のスコアが勝ちます。標準の抜け穴は許可されていません。

Haskellの簡単な実装例とテストスイートの定型文


7
人の上に来て、私はまだピックアップされるのを待っているいくつかの低ぶら下げフルーツのアルゴリズムがまだあると思います...
Angs

2
プログラムは平均重量/分布をハードコーディングできますか?(同様のバッチでも同様に機能すると仮定します。もちろん、限定的な先読みの目的を破壊するため、すべてがハードコーディングされているのは無効です)
user202729

@ user202729:はい、できます。
-Angs

とにかくすべてをハードコーディングすることは禁止された標準的な抜け穴です。
-Angs

私はlookheadあるものを見ることができない
l4m2

回答:


8

Python 3、9964 9981バッグ

このソリューションのアイデアは、Jonathan、JayCe、fortraanのアイデアと似ていますが、スコアリング関数=)

このソリューションは、先読みエリアの最適なサブセットをに追加しますscore

score 次のスキームを使用して、サブセットの順序を提供します。

  • バッグを完成させるサブセットは、そうでないものよりも優れています
  • バッグを完成させる1つのサブセットは、過剰な重量が少ない場合、他のサブセットよりも優れています
  • バッグを完成させていないサブセットは、平均がバッグの中にあると予想されるものに近い場合、別のサブセットよりも優れています

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)))

それを試してみてください!


非常に素晴らしい!7の先読みで1672を取得します。
-Angs

powersetこの場合、関数の2番目の引数はlen(list_)とにかく等しいので冗長なように見えますか?)
user202729

@user以前のバージョンでこのパラメーターを試しました。おそらく後で削除します
アレックス

1
最高のサブセットから最高の単一要素の強力な組み合わせを発見し、最高のスコアを獲得したことをおめでとうございます!報奨金はあなたのものです。
-Angs

シンプルexpected_mean(w)で良い結果が得られます:return (w+2) / max(1, round((w+2) / mean))
Angs

10

Python 3、9796バッグ

ジョナサンの答えに基づいて:

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のクックブックのpowersetに依存しています。最初に、すべてのサブセットのターゲットの重みとの差を最小化することに基づいてバッファーの最適なサブセットを見つけ、次に同じ基準に基づいてこのサブセットから要素を選択します。最適なサブセットがバッファ全体から選択されない場合。


PPCGへようこそ!
マーティンエンダー

@MartinEnder歓迎の賛辞を提供してくれたMartinに感謝します:)
JayCe

1
ああ、私はそこでトリックを逃しました...私はこれに別の答えとして問題ありません!
ジョナサンアラン

1
@JonathanAllanありがとうJonathan謝罪せずにあなたの名誉を称えるために私の答えを短くしました。これは、正規分布(170,13)であるという事実を使用することで改善できます。次の実行でより良い成果が得られる可能性が使用できると確信しています。
JayCe

@JayCeは、ギャンブラーの誤acyに危険なほど近いように聞こえます。
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(予測の長さ)。これを増やすと、プログラムが指数関数的に長くなります(バックトラックのため)
  • 繰り返し回数。これを増やすと、プログラムの実行が直線的に長くなります。

OK。シードを最良の答えを与えるものに変更することは、テストケースに対して最適化するように思えるので、スコアとしていくつかの、たとえば10個の異なるシードの平均を取る必要があります。ランタイムを下げるために繰り返しの少ないバージョンへのTIOリンクを投稿できますか?
Angs

最後に、新しいgccを取得してコンパイルしました。ランダムシードを使用した50回の実行では、平均9961.58になりました。まだとても印象的です。しかし、あなたのアルゴリズムは基本的にすべてのバッグで再び自分自身を訓練しますが、記憶できる最高の値の固定セットはありますか?
Angs

@Angsこの場合、暗記を使って助ける方法はないと思います。何か案が?
user202729

私のOSにはgcc 5.4.0が付属していますが、いくつかの問題がありましたinvalid use of template-name ‘std::normal_distribution’。gcc 7.1.0では問題ありません。
アンス


4

Python 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ユニットのフルーツが先読みリストの先頭に近いmin場合、101の代わりにそれを選択します。これが発生した場合、必要な残りの1ユニットを満たすために別のフルーツが必要になります。これらのケースでは、より価値の高い果物を優先するようにプログラムを変更しました。

これは、電源設定の前に先読みリストを並べ替えてから元に戻すことで行われます。


4

PHP、9975バッグ

  • 可能であれば、オレンジ5個を選びます
  • バッグの選択を開始するとき、極端な価値を取り、後でバランスを取る
  • 可能であれば、すぐに袋に入れてください
  • バッグの重量を推定曲線に近づけるようにしてください(5バッグではn * 200、6バッグでは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個のアイテムバッグを実行できる」というアイデアの簡単なショートカットとして出てきました。空き時間の改善が来る:)
mleko

3

Pythonの3、9855 9928 9947 9956 9964袋

ジョナサンアランのスターターコードに基づいていますが、読みやすいように変更されていません。

アイデア:1000/170 = 5.88以降、1000/6に近い果物を選択しようとします(魔法の定数をいじりました)。ただし、バッグの最後の果物が無駄を最小限に抑えることができる場合は、代わりにそれを使用します。

このソリューションには、追加された各フルーツのバッグ合計ターゲットがあります。おそらくここで停止します。Nelder-Meadを使用してtargets配列を見つけました。

[  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
良い!ところで、無駄を最小限に抑えるために最後のアイテムを選ぶだけで、それ自体は非常に強力で、9862個のバッグができます。
Angs

どうやってそれらを思いついたのtargetsですか?ランダムデータのトレーニング?
アレックス

1
@Alex私は次のように述べている。(損失関数として負バッグ付)ネルダ-ミード法
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

ラケット/スキーム、9800バッグ

袋に追加する果物を決定するには、最適な袋の重量と袋の重量を追加の果物と比較します。最適な重量であれば、それを使用します。太りすぎている場合は、過剰な量を最小限に抑えます。体重が不足している場合は、最適なギャップを残そうとして過剰な量を最小限に抑えます。

;; 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

Haskell、9981バッグ

Angsジョナサン・アランJayCefortraanアレックスローマCzyborra codegolfのpythonの思考の同じ主要な鉄道に沿っていくつかの追加の数学的な純度のためにハスケルに戻って環状化することができ

  • 新しいオレンジが考慮される前に、1つのオレンジだけが袋に入れられます
  • バイアスは果物の充足を好む((<miss)==False<True
  • バイアスは、最も可能性の高い整数塗りつぶしに近い果物を好む
  • その整数
    (m-n)/sqrt(n)==(n+1-m)/sqrt(n+1) <==> n=sqrt(m^2-1/4)-1/2https://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値する恵みはに行ってきましたアレックス

GIMME BOUNTY!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.