Meyve torbalama fabrikası


21

Amacınız, paketleme meyvesini bir taşıma bandından torbalara, perakendecilere gönderilmek üzere, en çok sayıda çanta için optimize etmek üzere optimize edebilen bir algoritma (program veya işlev) oluşturmaktır.

Her torba en az belirli bir ağırlıkta olmalıdır, fakat bu ağırlık başka bir çantayı doldurmak için kullanılabildiğinden fazla kar kaybedilir. Torbalama makineniz her zaman nkuyruktaki meyvelerin görünümüne sahiptir ve yalnızca bu nmeyvelerden herhangi birini işlenen (tek) torbaya eklemeyi seçebilir . nSıradaki ilk öğelerin ötesine bakamaz. Program her zaman çantada ne kadar ağırlık olduğunu tam olarak bilir.

Bunu görselleştirmenin bir başka yolu n, sonunda yeni bir meyve gelmeden önce bir meyvenin alınması gereken yükleme alanı büyüklüğünde bir taşıma bandına sahip olmaktır. Artık herhangi bir meyve ve sonunda dolu olmayan bir çanta atılır.

Şekil 1: Meyve torbalama fabrikası

Girdiler

  • Kuyruktaki meyvelerin ağırlık listesi / / (pozitif tamsayılar)
  • Çantalar için minimum toplam ağırlık (pozitif tamsayı)
  • Lookahead n(pozitif tamsayı)

Çıktı

Algoritmanız, tüm poşetler için, içindeki meyvelerin ağırlığını, sizin ve diliniz için ne uygunsa, stdin veya geri dönüş değeri veya başka bir şey için geri döndürmelidir. Programı çalıştırmak ve bilgisayarınızda bir dakika içinde puanınızı hesaplamak mümkün olmalıdır.

Örnek

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]

puanlama

Algoritmanız, altı uçta, sizin için hazırladığım 10000 portakallık bir partide , her iki uçta da dahil olmak üzere 2 ila 7 arasında değişen baklavalarda test edilecektir . Onları en az 1000 birim ağırlığındaki torbalara koyacaksınız. Portakallar normalde ortalama 170 ağırlık ve herhangi bir yardımı olması halinde 13 standart sapma ile dağıtılır.

Puanınız, altı turdaki çanta sayısının toplamı olacaktır. En yüksek puan kazanır. Standart boşluklara izin verilmez.

Haskell'de basit örnek uygulama ve test paketi kazanı


7
Hadi insanlar, hala alınmayı bekleyen bazı düşük asılı meyve algoritmaları hala olduğunu düşünüyorum ...
ANG'ler

2
Programlar ortalama ağırlık / dağılışı zorlayabilir mi? (benzer gruplar üzerinde eşit derecede iyi çalıştığını varsayalım, tabii ki
kodlama herşeyin

@ user202729: Evet yapabilirler.
Angs,

Ve her şeyi kodlama zaten yasak standart bir boşlukdur .
Angs,

Bakış açısının ne olduğunu göremiyorum
l4m2

Yanıtlar:


8

Python 3, 9964 9981 torbalar

Bu çözümün fikri Jonathan, JayCe ve fortraan'ınkilerle benzer, ancak puanlama işleviyle =)

Bu çözüm, göz alıcı alanın en iyi alt kümelerini buna göre ekler score.

score Aşağıdaki şemayı kullanarak alt kümeler üzerinde bir sipariş sağlar:

  • Bir torbayı tamamlayan bir altkümesi olmayan bir şeyden daha iyidir
  • Bir torbayı tamamlayan bir altküme, daha az aşırı ağırlığa sahipse, diğerinden daha iyidir
  • Bir torbayı tamamlamamış bir alt küme, ortalaması bir torbanın içinde olması beklenenden daha yakınsa, diğerinden daha iyidir.

expected_mean geri kalan değerlerin neye benzemesi gerektiğini tahmin etmeye çalışır (seçimlerinin optimum olduğunu varsayarak).

UPD :

İşte bir başka gözlem: En iyi alt kümeden herhangi bir portakalı algoritmanın performansına zarar vermeden torbaya yerleştirebilirsiniz. Herhangi bir parçasını hareket ettirmek, daha sonra geri kalanını hareket ettirmeye izin verir ve puanlama doğru ise kalan en iyi seçenek (yeni portakallar olmadan) olmalıdır. Dahası, bu şekilde, çanta doldurmadan önce daha fazla portakal görerek çantaya yerleştirilecek aday kümesini dinamik olarak iyileştirme şansı vardır. Ve mümkün olduğunca fazla bilgi edinmek istiyorsunuz, bu yüzden herhangi bir zamanda torbanın içine birden fazla portakal taşımanın hiçbir anlamı yoktur.

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

Dene!


Çok hoş! Bu 7 bir göz ile 1672 alır, hiç bu kadar yüksek görmedim.
Angs,

(Görünüşe göre, powersetişlevinizle ilgili ikinci argüman bu durumda gereksiz olduğu için gereksiz len(list_)mi?)
user202729 21.01.2007

@ user Önceki versiyonda bu parametre ile denedim. Muhtemelen daha sonra kaldıracak
Alex

1
En iyi alt kümeden en iyi tek elemanın güçlü kombinasyonunu keşfettiğiniz ve en iyi skoru elde ettiğiniz için tebrik ederiz! Ödül senindir.
Angs

expected_mean(w)İyi sonuçlar veren daha basit :return (w+2) / max(1, round((w+2) / mean))
Angs

10

Python 3 , 9796 poşetleri

Jonathan'ın cevabını geliştirmek:

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

Bu, itertool'un yemek kitabındaki powerset'e dayanıyor. İlk önce tüm alt kümeler için hedef ağırlıktan farkı en aza indirmeye dayanan tamponun optimal alt kümesini bulur ve daha sonra aynı kriteri temel alarak bu alt kümeden bir öğe seçer. En iyi altküme yoksa tüm tampondan seçim yapar.


PPCG'ye Hoşgeldiniz!
Martin Ender

@MartinEnder The welcoming upvote için teşekkürler Martin :)
JayCe

1
Ah evet orada bir hile özledim ... Başka bir cevap olarak bu konuda hiçbir sorunum yok!
Jonathan Allan,

1
@ JonathanathanAllan Jonathan Teşekkürler Özür dilerim sizi kredilendirmek için cevabımı kısaltdım. Bu normal (170,13) dağılım olduğu gerçeği kullanılarak geliştirilebilir - Bir sonraki çalışmada daha iyi bir meyve alma olasılığının kullanılabileceğinden eminim.
JayCe

@JayCe, kumarbazın yanıltmasına tehlikeli bir şekilde yakın geliyor.
qwr

6

C ++ 17, 9961.58 (bazı rastgele tohumlara göre ortalama)

(C ++ bilmiyorsanız açıklama için aşağı kaydırın)

#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';
}

// Eğlenceli gerçek: başlangıçta yazdığım <için >burada ve merak
// torba sayısı da az daha neden
// randomize algoritması

( <temelde kullanılırsa, algoritma çanta sayısını en aza indirmeye çalışır )

Bu cevaptan ilham aldım .

250 tekrarlama için TIO linki: Çevrimiçi deneyin!


Tanımlar bir işlev (aslında bu sadece bir fonksiyonu gibi görünüyor, bu bir yapı var) pick_orangeVerilen ki vector<int> weightsportakal ağırlık ve int remaintorbanın kalan ağırlığı, aldı edilmelidir turuncu dizinini döndürür.

Algoritma:

Tekrar 500kere {
üretir rastgele kalmayıncaya kadar (sahte) portakal (ortalama 170 ve stddev 13 ile normal bir dağılım) N_NEW_ORANGES=7portakal
olan toplamıdır küçüğüdür ve daha küçük olmayan herhangi bir alt kümesini almak remain(işlev backtrackolmadığını)
olarak söz konusu alt grubun tüm portakal işaretlemek iyiliği
}

Bir portakalın, eşit ağırlığı olan (gerçek) portakallardan daha iyi olarak işaretlenme sayısını ortalamaya
döndürün.


Programda problemden çıkarılamayan 3 sabit kod vardır:

  • Rastgele tohum (bu önemli değil)
  • N_NEW_ORANGES(tahmin uzunluğu). Bunun arttırılması programın katlanarak daha uzun çalışmasını sağlar (çünkü geri izleme)
  • tekrar sayısı. Bunun arttırılması programın doğrusal olarak daha uzun çalışmasını sağlar.

Tamam. Tohumun en iyi cevabı veren tohumla değiştirilmesi, test durumu için optimizasyon gibi gözüküyor, bu nedenle puanınız gibi birkaç, ortalama 10 farklı tohum almalısınız. Çalışma zamanını düşürmek için daha az tekrar yapan bir sürüme bir TIO bağlantısı gönderebilir misiniz?
Angs,

Sonunda yeni bir gcc aldıktan sonra derlemeyi başardı. Rastgele tohumlarla yapılan 50 koşuda ortalama 9961.58 oldu. Hala çok etkileyici. Yine de merak ettim - algoritmanız temelde her çantada kendini tekrar eğitiyor, ezberlenebilecek sabit en iyi değerler kümesi var mı?
Angs,

@Angs Bu durumda yardımcı olmak için ezberlemeyi kullanmanın bir yolu olduğunu sanmıyorum. Herhangi bir fikir?
user202729

İşletim sistemim gcc 5.4.0 ile birlikte geliyor, bazı problemleri vardı invalid use of template-name ‘std::normal_distribution’. Gcc ile sorun yok 7.1.0.
Angs,

4

Python 2,9756 çantaları

Turuncu yuvarlamayı alalım ...

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

Çevrimiçi deneyin!

Meyveyi daima yeni ağırlık ve hedef ağırlık arasındaki mutlak farkı en aza indiren tampondan alır.


4

Python 3, 9806 torba

Jonathan ve JayCe'nin cevaplarına dayanarak:

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

Çevrimiçi deneyin!

Nasıl çalışır

Torbanın içinde 900 adet olduğunu ve 2 tane meyve olduğunu söyleyin: 99 adet meyve ve 101 adet meyve. Eğer 99 ünite meyvesi gözetleme listesinin başına yakınsa min, 101 yerine onu seçecektir. Bu olursa, gerekli kalan 1 üniteyi yerine getirmek için şimdi başka bir meyveye ihtiyacımız olacaktır. Bu durumlarda daha yüksek değerli meyvelerin lehine olan programı değiştirdim.

Bunu, güç ayarlamadan önce sıralama listesini ve ardından bakış listesi listesini ters çevirerek yapar.


4

PHP, 9975 torba

  • Mümkünse 5 portakal için gidin
  • Torba aşırı değer seçmeye başlarken, daha sonra dengeleyin
  • Mümkünse derhal çanta doldurun
  • Torba ağırlığını tahmini eğriye yakın tutmaya çalışın (5 torba için n * 200, 6 torba için n * 167, vb.)

tüm başvurulardan en uzun ancak okunabilir olmalıdır

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 Toplam: 9975

Dene


Güzel! Benim için şaşırtıcı olan, şu anki ürün sayısını kullanmasıdır - merak edilebilecek olup olmadığını merak ediyorum. Sonuçta, her biri 120 ağırlığa sahip 3 madde veya her biri 160 ağırlığa sahip 3 madde olması farketmez.
Angs,

@Angs muhtemelen mümkün. Şu anki eşya sayımı, "Hey, bazen 5 eşya çantası yapmak bazen mümkün" fikri için basit bir kısayol olarak ortaya çıktı ve ben de 5 eşya çeki çalışmasına başladım. Serbest zaman iyileştirmeleri ile gelecektir :)
mleko

3

Python 3, 9855 9928 9947 9956 9964 çanta

Jonathan Allan'ın başlangıç ​​koduna göre, ama okunaklı olması yasak.

Fikir: 1000/170 = 5.88'den beri, 1000/6'ya yakın meyveler seçmeye çalışıyoruz (sihirli sabitlerle uğraştım). Ancak, torbadaki son meyve atıkları en aza indirebilirse, onu kullanırız.

Bu çözelti, eklenen her meyve için torba toplamı hedeflerine sahiptir. Muhtemelen burada duracağım. Dizimi bulmak için Nelder-Mead kullandım 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 çanta

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 çanta programı özellikle basittir:

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
İyi! BTW, atıkları en aza indirgemek için son ürünü seçmek sadece kendi başına oldukça güçlü ve 9862 torba veriyor.
Angs,

Bunları nasıl buldun targets? Rasgele veri eğitimi mi alıyorsunuz?
Alex,

1
@Alex Ben öyle dedim: Nelder-Mead yöntemi (kayıp fonksiyonu olarak negatif çantalar ile)
qwr

2

Yakut , 9967 çanta

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

Çevrimiçi deneyin!

Torbayı doldurmak için yeterli ağırlığınız varsa, torbayı doldurabilecek en hafif alt grubu bulun ve bu alt kümenin en açık turuncu rengini kullanın. Aksi takdirde, kalan ağırlığı 170 katına olabildiğince yaklaştırın.


2

Raket / Şema, 9880 torba

Torbaya hangi meyvenin ekleneceğine karar vermek için, torbanın ağırlığına uygun torbanın ağırlığını ek bir parça meyve ile karşılaştırın. En uygun ağırlık ise, kullanın. Aşırı kilolu ise, fazla miktarı en aza indirin. Düşük kiloluysa, en uygun boşluğu bırakmaya çalıştıktan sonra fazla miktarı en aza indirin.

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

Haskell , 9777 çanta

Bu benim ilk denememdi:

  • Açgözlülükle bir torbayı toplu halde doldurabildiğinde,
  • ya da bütün portakalları yiyemediklerinde poşete attı.
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]

Çevrimiçi deneyin!


1

Haskell , 9981 çanta

ANG'lerJonathan AllanJaycefortraanAlexRoman Czyborra codegolf piton düşünce aynı ana tren boyunca bazı ilave matematiksel saflık için Haskell geri siklize olabilen

bazı gereksiz anlamsızlıklarla terbiyeli

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]

Çevrimiçi deneyin!

hasat portakal 9981 ağlar üstünde farklı bir sayısal kazancı sağlayan olmadan yukarıda iken benim 10k011 torba elverişsiz portakal kapma tıkacın kapatılmamış çanta vazgeçme tarafından diskalifiye edildi user69850 içinde persona user202729Jo Kralovs hencefore hak kelle gitti Alex

GIMME BOUNTY!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.