Paradoks pembagian

10

Diberikan:

  • Sejumlah alami S .
  • Daftar bobot rasional W yang menjumlahkan ke 1.

Kembalikan daftar L dari N bilangan bulat non-negatif, sehingga:

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

Dengan kata lain, perkiraan S⋅W_is dengan bilangan bulat sedekat mungkin.

Contoh:

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]

Aturan:

  • Anda dapat menggunakan format input apa pun, atau hanya menyediakan fungsi yang menerima input sebagai argumen.

Latar Belakang:

Masalah ini muncul ketika menampilkan S dari berbagai jenis item dalam proporsi berbeda W i berkaitan dengan jenis.

Contoh lain dari masalah ini adalah perwakilan politik proporsional, lihat paradoks pembagian . Dua kasus uji terakhir dikenal sebagai Alabama paradox.

Sebagai ahli statistik, saya mengenali masalah ini sebagai setara dengan masalah yang ditemukan dalam mengidentifikasi ukuran sampel ketika melakukan sampel bertingkat. Dalam situasi itu, kami ingin membuat proporsi setiap strata dalam sampel sama dengan proporsi setiap strata dalam populasi. - @tomi

Glebm
sumber
Bisakah Anda mengatakan dengan kata-kata apa tugasnya? Saya mengalami kesulitan mendekompresi ekspresi menjadi sesuatu yang intuitif.
xnor
Keduanya harus ≤, diperbaiki. Tugasnya adalah menyajikan bilangan bulat sebagai jumlah bilangan bulat berdasarkan bobot. Sisanya harus didistribusikan dengan bobot tertinggi, meskipun saya tidak yakin persyaratan ini dikodekan dengan benar? Ini menarik karena round(A + B) != round(A) + round(B), solusi singkat memerlukan wawasan tentang apa yang terjadi di sini.
Glebm
1
Mungkin mengubah aturan untuk meminimalkan jumlah jarak L[i] - S*W[i]kuadrat, bukannya aturan 2 dan aturan 3. Ini akan mendekati S*W[i].
Jakube
1
Juga [0 1 2 2] merupakan solusi lain yang mungkin untuk5 [0.1 0.2 0.3 0.4]
Jakube
1
Mungkin Anda harus menambahkan contoh untuk 1 [0,4 0,3 0,3]
aditsu berhenti karena SE adalah JAHAT

Jawaban:

6

APL, 21

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

Ini adalah terjemahan dari jawaban CJam 37 byte aditsu .

Uji secara online .

Penjelasan

 {      ⍵-⍺}            ⍝ 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.
jimmy23013
sumber
7

Python 2, 95 83 132 125 143

Algoritma pertama (dan kedua) (dan ketiga) saya mengalami masalah sehingga setelah penulisan ulang (yang lain!) Dan lebih banyak pengujian, inilah (saya sangat berharap) solusi yang benar dan cepat:

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

Sumber sebelum minifier sekarang terlihat seperti:

# 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

Tes kembali:

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

Algoritma ini mirip dengan jawaban lain di sini. Ini adalah O (1) untuk num sehingga memiliki waktu berjalan yang sama untuk bilangan bulat 10 dan 1000000. Secara teoritis O (nlogn) untuk jumlah bobot (karena jenisnya). Jika ini tahan semua kasus input rumit lainnya, itu akan menggantikan algoritma di bawah ini di kotak alat pemrograman saya.

Tolong jangan gunakan algoritma itu dengan apa pun yang tidak golf. Saya membuat kompromi dalam kecepatan untuk meminimalkan ukuran sumber. Kode berikut menggunakan logika yang sama tetapi jauh lebih cepat dan lebih bermanfaat:

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

Nilai num tidak mempengaruhi kecepatan secara signifikan. Saya telah mengujinya dengan nilai dari 1 hingga 10 ^ 19. Waktu pelaksanaan bervariasi secara linear dengan jumlah bobot. Di komputer saya dibutuhkan 0,15 detik dengan bobot 10 ^ 5 dan 15 detik dengan bobot 10 ^ 7. Perhatikan bahwa bobot tidak terbatas pada fraksi yang berjumlah satu. Teknik pengurutan yang digunakan di sini juga sekitar dua kali lebih cepat dari sorted((v,i) for i,v in enumerate...)gaya tradisional .

Algoritma Asli

Ini adalah fungsi di kotak alat saya, dimodifikasi sedikit untuk golf. Ini berasal dari jawaban SO . Dan itu salah.

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

Ini memberikan perkiraan, tetapi tidak selalu benar, meskipun jumlah (outseq) == num dipertahankan. Cepat tapi tidak disarankan.

Terima kasih kepada @alephalpha dan @ user23013 untuk mengetahui kesalahannya.

EDIT: Tetapkan totalw (d) menjadi 1 karena OP menentukan jumlah bobot akan selalu menjadi 1. Sekarang 83 byte.

EDIT2: Fixed bug ditemukan untuk [0,4, 0,3, 0,3], 1.

EDIT3: Algoritma cacat yang ditinggalkan. Menambahkan yang lebih baik.

EDIT4: Ini menjadi konyol. Diganti dengan algoritma yang benar (saya sangat berharap demikian).

EDIT5: Menambahkan kode tidak-golf untuk orang lain yang mungkin ingin menggunakan algoritma ini.

Ksatria Logika
sumber
4
a([0.4, 0.3, 0.3], 1)kembali [0, 1, 0], sedangkan jawaban yang benar adalah [1, 0, 0].
alephalpha
1
Masih salah. a([0.11,0.3,0.59],4)dikembalikan [0, 1, 3]. Seharusnya [1, 1, 2].
jimmy23013
1
f([0.47,0.47,0.06],10)dikembalikan [5, 4, 1]. Seharusnya [5, 5, 0].
jimmy23013
2
Saya pikir itu benar sekarang.
jimmy23013
2
@CarpetPython Saya telah melalui proses yang serupa dengan algoritma ini, dan ini adalah bagaimana saya menemukan masalah ini. Jika mereka mengambil lisensi Anda, mereka juga harus mengambilnya :)
glebm
4

Mathematica, 67 50 46 45 karakter

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

Tidak Disatukan:

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]

Contoh:

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

{1, 1, 1, 2}

alephalpha
sumber
Ya ampun, itu pendek, mengingat itu Mathematica!
DavidC
3

CJam - 37

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

Cobalah online

Penjelasan:

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

Catatan:

  • Kompleksitasnya adalah tentang O (S * N), sehingga menjadi sangat lambat untuk S besar
  • CJam sangat kekurangan operator aritmatika untuk 2 array, sesuatu yang saya rencanakan untuk diterapkan nanti

Ide berbeda - 46

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

Cobalah online

Ini jauh lebih mudah dan efisien, tetapi sayangnya, sedikit lebih lama. Idenya di sini adalah mulai dengan L_i = lantai (S * W_i), tentukan perbedaan (katakanlah D) antara S dan jumlah mereka, temukan indeks D dengan bagian pecahan terbesar dari S * W_i (dengan menyortir dan mengambil D atas) dan kenaikan L_i untuk indeks tersebut. Kompleksitas O (N * log (N)).

aditsu berhenti karena SE adalah JAHAT
sumber
Sekarang ada O (N) :e<.
jimmy23013
@ user23013 oh yeah, untuk program pertama, terima kasih
aditsu berhenti karena SE adalah JAHAT
Itu tadi cepat! Selamat 🌟
glebm
Bagi mereka yang bertanya-tanya, mengganti pengurutan dengan algoritma pemilihan waktu linier akan menghasilkan O (n) alih-alih O yang sebenarnya (nlogn) yang disebabkan oleh pengurutan: Temukan elemen D-th terbesar, P, dalam O (N), kemudian naikkan elemen yang ≥PD kali (O (N) sejak D <= N).
Glebm
@ glebm itu cukup keren, tapi saya pikir ada masalah jika beberapa elemen memiliki nilai yang sama (P). Mungkin Anda bisa menyelesaikannya dalam 2 pass lalu: kenaikan pertama dan hitung elemen> P, maka Anda tahu berapa banyak elemen = P yang dibutuhkan. Atau jika Anda bisa mendapatkan informasi itu dari algoritma pemilihan, bahkan lebih baik.
Aditsu berhenti karena SE adalah JAHAT
3

JavaScript (ES6) 126 130 104 115 156 162 194

Setelah semua komentar dan test case dalam jawaban @ CarpetPython, kembali ke algoritma pertama saya. Sayangnya, solusi cerdas tidak berhasil. Implementasinya diperpendek sedikit, masih mencoba semua solusi yang mungkin, menghitung jarak kuadrat dan menjaga minimum.

Edit Untuk setiap elemen keluaran bobot w, 'semua' nilai yang mungkin hanya 2: trunc (w * s) dan trunc (w * s) +1, sehingga hanya ada (2 ** elemensts) solusi yang mungkin untuk dicoba.

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

Uji di Firefox / konsol FireBug

;[[ 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])))

Keluaran

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]

Itu solusi yang lebih cerdas. Lulus tunggal pada susunan bobot.
Untuk setiap pass saya menemukan nilai maks saat ini di w. Saya mengubah nilai ini di tempat dengan nilai integer tertimbang (dibulatkan), jadi jika s == 21 dan w = 0,4, kami mendapat 0,5 * 21 -> 10,5 -> 11. Saya menyimpan nilai ini dinegasikan, sehingga tidak bisa dapat ditemukan sebagai maks di loop berikutnya. Kemudian saya mengurangi jumlah total yang sesuai (s = s-11) dan juga mengurangi total bobot dalam variabel f.
Loop berakhir ketika tidak ada maks di atas 0 yang dapat ditemukan (semua nilai! = 0 telah dikelola).
Akhirnya saya mengembalikan nilai yang diubah menjadi positif lagi. Peringatan kode ini mengubah array bobot di tempat, sehingga harus dipanggil dengan salinan array asli

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)

Percobaan pertama saya

Bukan solusi yang cerdas. Untuk setiap kemungkinan hasil, ini mengevaluasi perbedaan, dan menjaga minimum.

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

Tidak Diikat Dan dijelaskan

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
}
edc65
sumber
2

CJam, 48 byte

Solusi lurus ke depan untuk masalah ini.

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

Inputnya seperti

[0.3 0.4 0.3] 4

Penjelasan:

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

Cobalah online di sini

Pengoptimal
sumber
2

Pyth: 40 byte

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

Ini mendefinisikan fungsi gdengan 2 parameter. Anda bisa menyebutnya seperti Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4.

Cobalah secara online: Pyth Compiler / Executor

Penjelasan:

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

Ini menciptakan semua solusi yang mungkin L, di mana L[i] = floor(S*W[i])atau L[i] = floor(S*W[i]+1). Misalnya, input 4 [0.3 0.4 0.3menciptakan [[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

Hanya [[2, 1, 1], [1, 2, 1], [1, 1, 2]]tinggal.

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 _
Jakube
sumber
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}


Penjelasan

Tidak disatukan

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]mengembalikan semua partisi integer s, menggunakan elemen yang diambil dari set {0, 1, 2, ...s}dengan batasan bahwa output harus mengandung jumlah elemen yang sama seperti pada set bobot w,.

Permutations memberikan semua pengaturan yang dipesan dari setiap partisi integer.

{Tr[(s *w-#)^2],#}mengembalikan daftar pasangan yang dipesan, {error, permutation} untuk setiap permutasi.

Sort[...] mengurutkan daftar {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]atau Part[<list>,{1,2}]mengembalikan item kedua dari elemen pertama dalam daftar diurutkan dari {{error, permutation}...}. Dengan kata lain, itu mengembalikan permutasi dengan kesalahan terkecil.

DavidC
sumber
2

R, 85 80 76

Menggunakan metode Kuota Kelinci.

Menghapus pasangan setelah melihat spesifikasi bahwa W akan berjumlah 1

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

Uji coba

> (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
>
MickyT
sumber
2

Python, 139 128 117 byte

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]

Solusi itertools sebelumnya, 139 byte

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]
Sp3000
sumber
Saya bertanya-tanya apakah solusi itertools mungkin. Kerja bagus +1. Apakah saya benar dalam berpikir ini memiliki kompleksitas waktu O (n ^ 4)?
Logic Knight
Solusi Itertools O(S^len(W))sebenarnya: P. Solusi baru jauh lebih cepat, tetapi masih lambat
Sp3000
2

Oktaf, 87 76

Golf:

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

Tidak Disatukan:

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

(Blasted "endfor" dan "endfunction"! Saya tidak akan pernah menang tetapi saya menikmati bermain golf dengan bahasa "nyata".)

dcsohl
sumber
Algoritma yang bagus. Anda bisa menggantinya zeros(size(w))dengan 0*w.
alephalpha
Bagus! Kenapa aku tidak memikirkan itu?
dcsohl
1

T-SQL, 167 265

Karena saya suka mencoba dan melakukan tantangan ini dalam kueri juga.

Mengubahnya menjadi fungsi inline agar lebih sesuai dengan spesifikasi dan membuat tipe untuk data tabel. Harganya sedikit, tapi ini tidak akan pernah menjadi pesaing. Setiap pernyataan harus dijalankan secara terpisah.

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

Digunakan

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
MickyT
sumber