Dağıtım paradoksu


10

Verilen:

  • Bir doğal sayı S .
  • 1'e karşılık gelen N rasyonel ağırlığın W listesi .

N negatif olmayan tamsayıların L listesini döndürün, böylece:

(1) sum(L) = S
(2) sum((S⋅W_i - L_i)^2) is minimal

Başka bir deyişle, S⋅W_itamsayılarla yaklaşık s mümkün olduğunca yakın.

Örnekler:

1 [0.4 0.3 0.3] = [1 0 0]
3 [0 1 0] = [0 3 0]
4 [0.3 0.4 0.3] = [1 2 1]
5 [0.3 0.4 0.3] = [2 2 1] or [1 2 2] but not [1 3 1]
21 [0.3 0.2 0.5] = [6 4 11]
5 [0.1 0.2 0.3 0.4] = [1 1 1 2] or [0 1 2 2]
4 [0.11 0.3 0.59] = [1 1 2]
10 [0.47 0.47 0.06] = [5 5 0]
10 [0.43 0.43 0.14] = [4 4 2]
11 [0.43 0.43 0.14] = [5 5 1]

Kurallar:

  • Herhangi bir girdi biçimini kullanabilir veya girdiyi bağımsız değişken olarak kabul eden bir işlev sağlayabilirsiniz.

Arka fon:

Bu sorun, türlere göre farklı oranlarda W i cinsinden farklı türde öğelerin S gösterilmesi sırasında ortaya çıkar .

Bu sorunun bir başka örneği orantılı siyasi temsildir , bkz. Paylaştırma paradoksu . Son iki test vakası Alabama paradoksu olarak bilinir.

Bir istatistikçi olarak, bu sorunu tabakalı bir örnek yürütürken örnek boyutlarının tanımlanmasında karşılaşılan bir probleme denk kabul ettim. Bu durumda, numunedeki her tabakanın oranını popülasyondaki her tabakanın oranına eşit yapmak istiyoruz. - @tomi


Görevin ne olduğunu kelimelerle söyleyebilir misiniz? İfadeleri sezgisel bir şeye açarken sorun yaşıyorum.
xnor

Her ikisi de ≤, sabit olmalıdır. Görev, bir tamsayıyı ağırlıklara dayalı tamsayıların toplamı olarak sunmaktır. Kalan en yüksek ağırlıkları tercih ederek dağıtmalıdır, ancak bu gereksinimin doğru kodlandığından emin değil miyim? Bu ilginç, çünkü round(A + B) != round(A) + round(B)kısa bir çözüm burada neler olduğuna dair bir fikir gerektiriyor.
glebm

1
Belki L[i] - S*W[i]kural 2 ve kural 3 yerine kare mesafelerin toplamını en aza indirmek için kuralları değiştirin S*W[i].
Jakube

1
Ayrıca [0 1 2 2] başka bir olası çözüm5 [0.1 0.2 0.3 0.4]
Jakube

1
Belki 1 için bir örnek eklemelisiniz [0.4 0.3 0.3]
aditsu quit çünkü SE EVIL

Yanıtlar:


6

APL, 21

{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}

Bu, aditsu'nun 37 bayt CJam yanıtından bir çeviridir .

Çevrimiçi test edin .

açıklama

 {      ⍵-⍺}            ⍝ Right argument - left argument.
 {  1=⍋⍋⍵-⍺}            ⍝ Make one of the smallest number 1, others 0.
 {⍵+1=⍋⍋⍵-⍺}            ⍝ Add the result and the right argument together.
 {⍵+1=⍋⍋⍵-⍺}⍣⍺          ⍝ Repeat that S times. The result of each iteration is the new right argument.
                  ⊂⍵    ⍝ Return enclosed W, which is taken as one unit in APL.
               ⍺0×⊂⍵    ⍝ Return S*W and 0*W.
{{⍵+1=⍋⍋⍵-⍺}⍣⍺/⍺0×⊂⍵}   ⍝ Make S*W the left argument, 0*W the right argument in the first iteration.

7

Piton 2, 95 83 132 125 143

Birinci (ve ikinci) (ve üçüncü) algoritmamın sorunları vardı, bu yüzden (başka!) Yeniden yazma ve daha fazla testten sonra, (gerçekten umarım) doğru ve hızlı bir çözümdür:

def a(b,h):
 g=h;c=[];d=[]
 for w in b:f=int(w*h);d+=[f];c+=[h*w-f];g-=f
 if g:
  for e in sorted(c)[-g:]:i=c.index(e);c[i]=2;d[i]+=1
 return d

Küçültücüden önceki kaynak şu şekilde görünüyor:

# minified 143 bytes
def golfalloc(weights, num):
    # Tiny seq alloc for golfing
    gap = num;
    errors = [];
    counts = []
    for w in weights :
        count = int(w*num);
        counts += [count];
        errors += [num*w - count];
        gap -= count
    if gap:
        for e in sorted(errors)[-gap:] :
            i = errors.index(e);
            errors[i] = 2;
            counts[i] += 1
    return counts

Testler geri dönüyor:

Pass                    Shape    N               Result Error                        AbsErrSum
ok            [0.4, 0.3, 0.3]    1            [1, 0, 0] -0.60,+0.30,+0.30                 1.20
ok                  [0, 1, 0]    3            [0, 3, 0] +0.00,+0.00,+0.00                 0.00
ok            [0.3, 0.4, 0.3]    4            [1, 2, 1] +0.20,-0.40,+0.20                 0.80
ok            [0.3, 0.4, 0.3]    5            [2, 2, 1] -0.50,+0.00,+0.50                 1.00
ok            [0.3, 0.2, 0.5]   21           [6, 4, 11] +0.30,+0.20,-0.50                 1.00
ok       [0.1, 0.2, 0.3, 0.4]    5         [1, 1, 1, 2] -0.50,+0.00,+0.50,+0.00           1.00
ok          [0.11, 0.3, 0.59]    4            [1, 1, 2] -0.56,+0.20,+0.36                 1.12
ok         [0.47, 0.47, 0.06]   10            [5, 5, 0] -0.30,-0.30,+0.60                 1.20
ok         [0.43, 0.43, 0.14]   10            [4, 4, 2] +0.30,+0.30,-0.60                 1.20
ok         [0.43, 0.43, 0.14]   11            [5, 5, 1] -0.27,-0.27,+0.54                 1.08

Bu algoritma buradaki diğer cevaplara benzer. Num için O (1) 'dir, bu nedenle 10 ve 1000000 tamsayıları için aynı çalışma süresine sahiptir. Teorik olarak ağırlıkların sayısı (sıralama nedeniyle) için O (nlogn)' dir. Bu, diğer tüm zor giriş durumlarına dayanırsa, programlama araç kutumdaki aşağıdaki algoritmanın yerini alacaktır.

Lütfen bu algoritmayı golf amaçlı olmayan bir şeyle kullanmayın. Kaynak boyutunu en aza indirmek için hızdan ödün verdim. Aşağıdaki kod aynı mantığı kullanır, ancak çok daha hızlı ve daha kullanışlıdır:

def seqalloc(anyweights, num):
    # Distribute integer num depending on weights.
    # weights may be non-negative integers, longs, or floats.
    totalbias = float(sum(anyweights))
    weights = [bias/totalbias for bias in anyweights]
    counts = [int(w*num) for w in weights]
    gap = num - sum(counts)
    if gap:
        errors = [num*w - q for w,q in zip(weights, counts)]
        ordered = sorted(range(len(errors)), key=errors.__getitem__)
        for i in ordered[-gap:]:
            counts[i] += 1
    return counts

Num değeri hızı önemli ölçüde etkilemez. 1 ile 10 ^ 19 arasındaki değerlerle test ettim. Uygulama süresi ağırlık sayısına göre doğrusal olarak değişir. Bilgisayarımda 10 ^ 5 ağırlık ile 0.15 saniye ve 10 ^ 7 ağırlık ile 15 saniye sürüyor. Ağırlıklar, bire denk gelen kesirlerle sınırlı değildir. Burada kullanılan ayırma tekniği de geleneksel sorted((v,i) for i,v in enumerate...)tarzın iki katı kadar hızlıdır .

Orijinal Algoritma

Bu, alet kutumdaki bir işlevdi, golf için biraz değiştirildi. Başlangıçta bir SO cevabından geliyordu . Ve bu yanlış.

def seqalloc(seq, num):
    outseq = []
    totalw = float(sum(seq))
    for weight in seq:
        share = int(round(num * weight / totalw)) if weight else 0
        outseq.append(share)
        totalw -= weight
        num -= share
    return outseq

Toplam (outseq) == num korunmasına rağmen, yaklaşık bir değer verir, ancak her zaman doğru değildir. Hızlı ama önerilmez.

Hataları tespit ettikleri için @ alephalpha ve @ user23013'e teşekkürler.

DÜZENLEME: OP toplam ağırlık her zaman 1 olacağını belirttiği için totalw (d) değerini 1 olarak ayarlayın. Şimdi 83 bayt.

EDIT2: [0.4, 0.3, 0.3], 1 için sabit hata bulundu.

EDIT3: Terk edilmiş hatalı algoritma. Daha iyisi eklendi.

EDIT4: Bu çok saçma oluyor. Doğru (gerçekten umarım) algoritması ile değiştirildi.

EDIT5: Bu algoritmayı kullanmak isteyebilecek diğerleri için golf dışı kod eklendi.


4
a([0.4, 0.3, 0.3], 1)[0, 1, 0]doğru cevap ise döner [1, 0, 0].
alephalpha

1
Hala yanlış. a([0.11,0.3,0.59],4)döndü [0, 1, 3]. Olmalı [1, 1, 2].
jimmy23013

1
f([0.47,0.47,0.06],10)döndü [5, 4, 1]. Olmalı [5, 5, 0].
jimmy23013

2
Sanırım şimdi doğru.
jimmy23013

2
@CarpetPython Bu algoritma ile benzer bir süreçten geçtim ve bu sorunu bu şekilde ortaya çıkardım. Lisansınızı alırlarsa, benimkini de
almalılar

4

Mathematica, 67 50 46 45 karakter

f=(b=⌊1##⌋;b[[#~Ordering~-Tr@#&[b-##]]]++;b)&

Ungolfed:

f[s_, w_] := Module[{a = s*w, b, c, d},
  b = Floor[a];
  c = b - a;
  d = Ordering[c, -Total[c]];
  b[[d]] += 1;
  b]

Misal:

f[5,{0.1,0.2,0.3,0.4}]

{1, 1, 1, 2}


Tanrım, bu Mathematica göz önüne alındığında kısa!
DavidC

3

CJam - 37

q~:W,0a*\:S{[_SWf*]z::-_:e<#_2$=)t}*p

Çevrimiçi deneyin

Açıklama:

q~             read and evaluate the input
               (pushing the number and the array on the stack)
:W,            save the array in variable W and calculate its length (N)
0a*            make an array of N zeros (the initial "L")
\:S            swap it with the number and save the number in S
{…}*           execute the block S times
    [_SWf*]    make a matrix with 2 rows: "L" and S*W
    z          transpose the matrix, obtaining rows of [L_i S*W_i]
    ::-_       convert to array of L_i-S*W_i and duplicate
    :e<        get the smallest element
    #          find its index in the unsorted array,
               i.e. the "i" with the largest S*W_i-L_i
    _2$=)t     increment L_i
p              print the result nicely

Notlar:

  • Karmaşıklık O (S * N) hakkındadır, bu nedenle büyük S için gerçekten yavaşlar
  • CJam, 2 dizide aritmetik işleçlerden yoksundur, daha sonra uygulamayı planlıyorum

Farklı fikir - 46

q~:Sf*_:m[_:+S\-@[1f%_,,]z{0=W*}$<{1=_2$=)t}/p

Çevrimiçi deneyin

Bu çok daha basit ve verimli, ama ne yazık ki, biraz daha uzun. Buradaki fikir, L_i = zemin (S * W_i) ile başlamak, S ve toplamları arasındaki farkı (D demek) belirlemek, S * W_i'nin en büyük kesirli kısmına sahip D endekslerini bulmak (sıralama ve üst D'yi alarak) ve bu endeksler için L_i değerini artırın. Karmaşıklık O (N * log (N)).


Şimdi O (N) var :e<.
jimmy23013

@ user23013 oh evet, ilk program için teşekkürler
aditsu quit çünkü SE EVIL

Bu hızlı oldu! Tebrikler 🌟
glebm

Merak edenler için, sıralamanın doğrusal bir zaman seçim algoritması ile değiştirilmesi, sıralamanın neden olduğu gerçek O (nlogn) yerine O (n) verir: O (N) 'de D. En büyük elemanı P, sonra artırın D <= N'den beri timesPD çarpı (O (N)) elemanlar.
glebm

@glebm bu çok güzel, ama bence birden fazla öğe aynı değere sahipse bir sorun var (P). Belki bunu 2 geçişte çözebilirsiniz: ilk önce arttırma ve elemanları sayma> P, sonra kaç eleman = P gerektiğini biliyorsunuz. Ya da bu bilgiyi seçim algoritmasından alabiliyorsanız, daha da iyi.
aditsu bıraktı çünkü SE EVIL

3

JavaScript (ES6) 126 130 104 115 156 162 194

@ CarpetPython'un cevabındaki tüm yorumlar ve test durumlarından sonra, ilk algoritmam. Ne yazık ki, akıllı çözüm çalışmıyor. Uygulama biraz kısaldı, hala tüm olası çözümleri deniyor, kare mesafeyi kireçliyor ve minimumda tutuyor.

Düzenle w ağırlığının her çıkış öğesi için, 'all' olası değerleri sadece 2'dir: trunc (w * s) ve trunc (w * s) +1, bu yüzden denemek için sadece (2 ** elemenst) olası çözüm vardır.

Q=(s,w)=>
  (n=>{
    for(i=0;
        r=q=s,(y=i++)<1<<w.length;
        q|r>n||(n=r,o=t))
      t=w.map(w=>(f=w*s,q-=d=0|f+(y&1),y/=2,f-=d,r+=f*f,d));
  })()||o

Firefox / FireBug konsolunda test et

;[[ 1,  [0.4, 0.3, 0.3]      ]
, [ 3,  [0, 1, 0]            ]
, [ 4,  [0.3, 0.4, 0.3]      ]
, [ 5,  [0.3, 0.4, 0.3]      ]
, [ 21, [0.3, 0.2, 0.5]      ]
, [ 5,  [0.1, 0.2, 0.3, 0.4] ]
, [ 4,  [0.11, 0.3, 0.59]    ]
, [ 10, [0.47, 0.47, 0.06]   ]
, [ 10, [0.43, 0.43, 0.14]   ]
, [ 11, [0.43, 0.43, 0.14]   ]]
.forEach(v=>console.log(v[0],v[1],Q(v[0],v[1])))

Çıktı

1 [0.4, 0.3, 0.3] [1, 0, 0]
3 [0, 1, 0] [0, 3, 0]
4 [0.3, 0.4, 0.3] [1, 2, 1]
5 [0.3, 0.4, 0.3] [1, 2, 2]
21 [0.3, 0.2, 0.5] [6, 4, 11]
5 [0.1, 0.2, 0.3, 0.4] [0, 1, 2, 2]
4 [0.11, 0.3, 0.59] [1, 1, 2]
10 [0.47, 0.47, 0.06] [5, 5, 0]
10 [0.43, 0.43, 0.14] [4, 4, 2]
11 [0.43, 0.43, 0.14] [5, 5, 1]

Bu daha akıllı bir çözüm. Ağırlık dizisinde tek geçiş.
Her geçişte mevcut maksimum değeri w olarak bulurum. Bu değeri ağırlıklı tamsayı değeriyle (yuvarlanmış) yerinde değiştiririm, bu nedenle s == 21 ve w = 0.4 ise, 0,5 * 21 -> 10,5 -> 11 değerini alırım. sonraki döngüde maks. Daha sonra toplamı buna göre (s = s-11) azaltır ve ayrıca f değişkenindeki ağırlıkların toplamını da azaltırım.
Döngü, bulunacak maks. 0'dan büyük olmadığında sona erer (tüm değerler! = 0 yönetilmiştir).
Sonunda tekrar pozitif olarak değiştirilen değerleri döndürürüm. Uyarı orijinal dizinin bir kopyası ile çağrılmalıdır böylece yerinde ağırlıkları dizisi, bu kodu tadil etmektedir

F=(s,w)=>
 (f=>{
  for(;j=w.indexOf(z=Math.max(...w)),z>0;f-=z)
    s+=w[j]=-Math.ceil(z*s/f);
 })(1)||w.map(x=>0-x)

İlk denemem

Çok akıllı bir çözüm değil. Olası her sonuç için farkı değerlendirir ve minimum tutar.

F=(s,w,t=w.map(_=>0),n=NaN)=>
  (p=>{
    for(;p<w.length;)
      ++t[p]>s?t[p++]=0
      :t.map(b=>r+=b,r=p=0)&&r-s||
        t.map((b,i)=>r+=(z=s*w[i]-b)*z)&&r>n||(n=r,o=[...t])
  })(0)||o

Ungolfed Ve açıkladı

F=(s, w) =>
{
  var t=w.map(_ => 0), // 0 filled array, same size as w
      n=NaN, // initial minumum NaN, as "NaN > value"  is false for any value
      p, r
  // For loop enumerating from [1,0,0,...0] to [s,s,s...s]
  for(p=0; p<w.length;)
  {
    ++t[p]; // increment current cell
    if (t[p] > s)
    {
      // overflow, restart at 0 and point to next cell
      t[p] = 0;
      ++p;
    }
    else
    {
      // increment ok, current cell is the firts one
      p = 0;
      r = 0;
      t.map(b => r += b) // evaluate the cells sum (must be s)
      if (r==s)
      {
        // if sum of cells is s
        // evaluate the total squared distance (always offset by s, that does not matter)
        t.map((b,i) => r += (z=s*w[i]-b)*z) 
        if (!(r > n))
        {
          // if less than current mininum, keep this result
          n=r
          o=[...t] // copy of t goes in o
        }
      }
    }
  }
  return o
}

2

CJam, 48 bayt

Soruna doğrudan bir çözüm.

q~:Sf*:L,S),a*{m*{(+}%}*{1bS=},{L]z::-Yf#:+}$0=p

Girdi şöyle gidiyor

[0.3 0.4 0.3] 4

Açıklama:

q~:S                                 "Read and parse the input, store sum in S";
    f*:L                             "Do S.W, store the dot product in L";
         S),                         "Get array of 0 to S";
        ,   a*                       "Create an array with N copies of the above array";
              {m*{(+}%}*             "Get all possible N length combinations of 0 to S ints";
                        {1bS=},      "Filter to get only those which sum up to S";
{L]z::-Yf#:+}$                       "Sort them based on (S.W_i - L_i)^2 value";
 L                                   "Put the dot product after the sum combination";
  ]z                                 "Wrap in an array and transpose";
    ::-                              "For each row, get difference, i.e. S.W_i - L_i";
       Yf#                           "Square every element";
          :+                         "Take sum";
              0=p                    "After sorting on sum((S.W_i - L_i)^2), take the";
                                     "first element, i.e. smallest sum and print it";

Buradan çevrimiçi deneyin


2

Pyth: 40 bayt

Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUH

Bu, g2 parametreli bir işlevi tanımlar . Buna şöyle diyebilirsiniz Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4.

Çevrimiçi deneyin: Pyth Derleyici / Yönetici

Açıklama:

mms+*G@Hb}bklHyUH     (G is S, H is the list of weights)
m             yUH    map each subset k of [0, 1, ..., len(H)-1] to:
 m          lH          map each element b of [0, 1, ..., len(H)-1] to: 
    *G@Hb                  G*H[b]
   +     }bk               + b in k
  s                       floor(_)

Bu, tüm olası çözümler yaratır L, L[i] = floor(S*W[i])ya da L[i] = floor(S*W[i]+1). Örneğin, girdi 4 [0.3 0.4 0.3oluşturur [[1, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 2]].

fqsTG...  
f    ... only use the solutions, where
 qsTG       sum(solution) == G

Sadece [[2, 1, 1], [1, 2, 1], [1, 1, 2]]kal.

Mhosm^-*Ghded2C,HN
  o                  order the solutions by
   s                   the sum of 
    m         C,HN       map each element d of zip(H, solution) to
     ^-*Ghded2           (G*d[0] - d[1])^2
 h                   use the first element (minimum)
M                    define a function g(G,H): return _

2

Mathematica 108

s_~f~w_:=Sort[{Tr[(s*w-#)^2],#}&/@ 
Flatten[Permutations/@IntegerPartitions[s,{Length@w},0~Range~s],1]][[1,2]]

f[3, {0, 1, 0}]
f[4, {0.3, 0.4, 0.3}]
f[5, {0.3, 0.4, 0.3}]
f[21, {0.3, 0.2, 0.5}]
f[5, {0.1, 0.2, 0.3, 0.4}]

{0, 3, 0}
{1, 2, 1}
{1, 2, 2}
{6, 4, 11}
{0, 1, 2, 2}


açıklama

Ungolfed

f[s_,w_]:=
Module[{partitions},
partitions=Flatten[Permutations/@IntegerPartitions[s,{Length[w]},Range[0,s]],1];
Sort[{Tr[(s *w-#)^2],#}&/@partitions][[1,2]]]

IntegerPartitions[s,{Length@w},0~Range~s]çıktının ağırlık kümesindeki ile aynı sayıda eleman içermesi gerektiği sınırlamasıyla skümeden alınan elemanları kullanarak tüm tamsayı bölümlerini döndürür .{0, 1, 2, ...s}w

Permutations her tamsayı bölümünün tüm sıralı düzenlemelerini verir.

{Tr[(s *w-#)^2],#}{error, permutation} her permütasyon için sıralı çiftlerin bir listesini döndürür .

Sort[...] listesini sıralar {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]veya Part[<list>,{1,2}]öğesinin sıralanmış listesindeki ilk öğenin ikinci öğesini döndürür {{error, permutation}...}. Başka bir deyişle, permütasyonu en küçük hatayla döndürür.


2

R, 85 80 76

Hare Kota yöntemini kullanır.

W toplamı spec gördükten sonra bir çift kaldırıldı 1

function(a,b){s=floor(d<-b*a);s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s}

Test sürüşü

> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(3,c(0,1,0))
[1] 0 3 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(1,c(0.4,0.3,0.3))
[1] 1 0 0
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(4,c(0.3, 0.4, 0.3))
[1] 1 2 1
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.3, 0.4, 0.3))
[1] 1 2 2
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(21,c(0.3, 0.2, 0.5))
[1]  6  4 11
> (function(a,b){s=floor(d<-b/(sum(b)/a));s[o]=s[o<-rev(order(d%%1))[0:(a-sum(s))]]+1;s})(5,c(0.1,0.2,0.3,0.4))
[1] 1 1 1 2
>

2

Python, 139 128 117 bayt

def f(S,W):
 L=(S+1,0,[]),
 for n in W:L=[(x-i,y+(S*n-i)**2,z+[i])for x,y,z in L for i in range(x)]
 return min(L)[2]

Önceki itertools çözümü, 139 bayt

from itertools import*
f=lambda S,W:min((sum(x)!=S,sum((S*a-b)**2for a,b in zip(W,x)),list(x))for x in product(*tee(range(S+1),len(W))))[2]

Bir itertools çözümünün mümkün olup olmadığını merak ediyordum. İyi iş +1. Bunun O (n ^ 4) zaman karmaşıklığı olduğunu düşünmekte haklı mıyım?
Mantık Şövalyesi

Itertools çözeltisi O(S^len(W))aslında: P. Yeni çözüm çok daha hızlı, ama yine de yavaş
Sp3000

2

Oktav, 87 76

golfed:

function r=w(s,w)r=0*w;for(i=1:s)[m,x]=max(s*w-r);r(x)+=1;endfor endfunction

Ungolfed:

function r=w(s,w)
  r=0*w;   # will be the output
  for(i=1:s)
    [m,x]=max(s*w-r);
    r(x)+=1;
  endfor
endfunction

(Püskürdü "endfor" ve "endfunction"! Asla kazanmayacağım ama "gerçek" bir dille golf oynamaktan zevk alıyorum.)


Güzel algoritma. Sen yerini alabilir zeros(size(w))ile 0*w.
alephalpha

Güzel! Neden böyle düşünmedim?
dcsohl

1

T-SQL, 167 265

Çünkü bu zorlukları bir sorguda da denemeyi seviyorum.

Spesifikasyona daha iyi uyması için bir satır içi fonksiyona dönüştürdü ve tablo verileri için bir tür oluşturdu. Biraz maliyeti vardı, ama bu asla bir rakip olmayacaktı. Her ifadenin ayrı çalıştırılması gerekir.

CREATE TYPE T AS TABLE(A INT IDENTITY, W NUMERIC(9,8))
CREATE FUNCTION W(@ int,@T T READONLY)RETURNS TABLE RETURN SELECT CASE WHEN i<=@-SUM(g)OVER(ORDER BY(SELECT\))THEN g+1 ELSE g END R,A FROM(SELECT A,ROW_NUMBER()OVER(ORDER BY (W*@)%1 DESC)i,FLOOR(W*@)g FROM @T)a

Kullanımda

DECLARE @ INT = 21
DECLARE @T T
INSERT INTO @T(W)VALUES(0.3),(0.2),(0.5)
SELECT R FROM dbo.W(@,@T) ORDER BY A

R
---------------------------------------
6
4
11
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.