การจัดสรรความขัดแย้ง


10

ได้รับ:

  • จำนวนธรรมชาติS
  • รายการน้ำหนัก N เหตุผลWที่รวมเป็น 1

ส่งคืนรายการLของ N จำนวนเต็มไม่ใช่ลบเช่น:

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

กล่าวอีกนัยหนึ่งคือประมาณS⋅W_iด้วยจำนวนเต็มที่สุด

ตัวอย่าง:

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]

กฎ:

  • คุณสามารถใช้รูปแบบอินพุตใด ๆ ก็ได้หรือเพียงแค่จัดเตรียมฟังก์ชันที่รับอินพุตเป็นอาร์กิวเมนต์

พื้นหลัง:

ปัญหานี้เกิดขึ้นเมื่อแสดงSของรายการประเภทต่าง ๆ ในสัดส่วนที่แตกต่างกันW iตามประเภท

ตัวอย่างของปัญหานี้ก็คือการเป็นตัวแทนทางการเมืองสัดส่วนให้ดูที่ความขัดแย้งแบ่งปัน กรณีทดสอบสองครั้งล่าสุดเป็นที่รู้จักกันในชื่อ Alabama Paradox

ในฐานะนักสถิติฉันรับรู้ปัญหานี้ว่าเทียบเท่ากับปัญหาที่พบในการระบุขนาดตัวอย่างเมื่อดำเนินการตัวอย่างแบบแบ่งชั้น ในสถานการณ์นั้นเราต้องการให้สัดส่วนของแต่ละชั้นในตัวอย่างเท่ากับสัดส่วนของแต่ละชั้นในประชากร - @tomi


คุณสามารถพูดด้วยคำพูดว่างานเป็นอย่างไร ฉันมีปัญหาในการคลายการแสดงออกในสิ่งที่ใช้งานง่าย
xnor

ทั้งคู่ควรเป็น≤คงที่ ภารกิจคือการนำเสนอจำนวนเต็มเป็นผลรวมของจำนวนเต็มตามน้ำหนัก ส่วนที่เหลือควรกระจายน้ำหนักสูงสุดถึงแม้ว่าฉันไม่แน่ใจว่าข้อกำหนดนี้ถูกเข้ารหัสอย่างถูกต้องหรือไม่ สิ่งนี้น่าสนใจเพราะround(A + B) != round(A) + round(B)โซลูชันสั้น ๆ ต้องการข้อมูลเชิงลึกเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่
glebm

1
บางทีการเปลี่ยนแปลงกฎระเบียบเพื่อลดผลรวมของระยะทางที่L[i] - S*W[i]ยกกำลังสองแทนกฎ 2 และกฎ 3 S*W[i]นี้จะใกล้เคียงกับ
Jakube

1
นอกจากนี้ยัง[0 1 2 2] เป็นอีกหนึ่งทางออกที่เป็นไปได้สำหรับ5 [0.1 0.2 0.3 0.4]
Jakube

1
บางทีคุณควรจะเพิ่มตัวอย่างสำหรับ 1 [0.4 0.3 0.3]
aditsu ออกเพราะ SE เป็นความชั่วร้าย

คำตอบ:


6

APL, 21

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

นี่คือการแปลจาก37 ไบต์คำตอบ

ทดสอบออนไลน์

คำอธิบาย

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

Python 2, 95 83 132 125 143

อัลกอริทึมแรก (และที่สอง) (และที่สาม) ของฉันมีปัญหาดังนั้นหลังจาก (อีกครั้ง!) เขียนใหม่และทดสอบมากขึ้นต่อไปนี้คือ (ฉันหวังจริงๆ) วิธีแก้ปัญหาที่ถูกต้องและรวดเร็ว:

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

แหล่งที่มาก่อน minifier ตอนนี้ดูเหมือนว่า:

# 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

การทดสอบกลับมา:

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

อัลกอริทึมนี้คล้ายกับคำตอบอื่น ๆ ที่นี่ มันคือ O (1) สำหรับ num ดังนั้นจึงมีเวลาทำงานเท่ากันสำหรับจำนวนเต็ม 10 และ 1000000 มันเป็นตามทฤษฎี O (nlogn) สำหรับจำนวนน้ำหนัก (เนื่องจากการเรียงลำดับ) หากสิ่งนี้ทนทานต่อกรณีอินพุตที่ยุ่งยากอื่น ๆ ทั้งหมดก็จะแทนที่อัลกอริทึมด้านล่างในกล่องเครื่องมือการเขียนโปรแกรมของฉัน

โปรดอย่าใช้อัลกอริทึมนั้นกับสิ่งใดที่ไม่ใช่กอล์ฟ ฉันใช้ความเร็วเพื่อลดขนาดแหล่งข้อมูล รหัสต่อไปนี้ใช้ตรรกะเดียวกัน แต่เร็วกว่าและมีประโยชน์มากกว่า:

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 ไม่ส่งผลกระทบต่อความเร็วอย่างมีนัยสำคัญ ฉันทดสอบด้วยค่าตั้งแต่ 1 ถึง 10 ^ 19 เวลาดำเนินการแตกต่างกันไปตามจำนวนน้ำหนัก ในคอมพิวเตอร์ของฉันใช้เวลา 0.15 วินาทีกับน้ำหนัก 10 ^ 5 และ 15 วินาทีกับน้ำหนัก 10 ^ 7 โปรดทราบว่าน้ำหนักไม่ได้ จำกัด อยู่เพียงเศษส่วนที่รวมเป็นหนึ่ง เทคนิคการจัดเรียงที่ใช้ที่นี่ก็เร็วขึ้นเป็นสองเท่าของsorted((v,i) for i,v in enumerate...)สไตล์ดั้งเดิม

อัลกอริทึมดั้งเดิม

นี่คือฟังก์ชั่นในกล่องเครื่องมือของฉันแก้ไขเล็กน้อยสำหรับการเล่นกอล์ฟ แต่เดิมมันเป็นจากคำตอบ SO และมันก็ผิด

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

มันให้การประมาณค่า แต่ไม่ถูกต้องเสมอไปแม้ว่าจะยังคงผลรวม (outseq) == จำนวน เร็ว แต่ไม่แนะนำ

ขอบคุณ @alephalpha และ @ user23013 สำหรับการตรวจพบข้อผิดพลาด

แก้ไข: ตั้งค่า totalw (d) เป็น 1 เนื่องจาก OP ระบุผลรวมของน้ำหนักที่จะเป็น 1 เสมอตอนนี้ 83 ไบต์

EDIT2: แก้ไขข้อผิดพลาดที่พบสำหรับ [0.4, 0.3, 0.3], 1

EDIT3: อัลกอริทึมข้อบกพร่องที่ถูกทอดทิ้ง เพิ่มเข้ามาดีกว่า

แก้ไข 4: นี่คือการไร้สาระ แทนที่ด้วยอัลกอริทึมที่ถูกต้อง (ฉันหวังจริงๆ)

EDIT5: เพิ่มรหัสไม่กอล์ฟสำหรับผู้อื่นที่อาจต้องการใช้อัลกอริทึมนี้


4
a([0.4, 0.3, 0.3], 1)ผลตอบแทนในขณะที่คำตอบที่ถูกต้องคือ[0, 1, 0] [1, 0, 0]
alephalpha

1
ยังคงผิด กลับa([0.11,0.3,0.59],4) ควรจะเป็น[0, 1, 3] [1, 1, 2]
jimmy23013

1
f([0.47,0.47,0.06],10)[5, 4, 1]กลับ [5, 5, 0]ควรจะเป็น
jimmy23013

2
ฉันคิดว่ามันถูกต้องแล้ว
jimmy23013

2
@CarpetPython ฉันใช้กระบวนการที่คล้ายกันกับอัลกอริทึมนี้และนี่คือวิธีที่ฉันพบปัญหานี้ หากพวกเขานำใบอนุญาตของคุณออกไปพวกเขาก็ควรจะขุดด้วยเช่นกัน :)
glebm

4

Mathematica, 67 50 46 45 ตัวอักษร

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]

ตัวอย่าง:

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

{1, 1, 1, 2}


ความดีของฉันนั้นสั้นถือว่าเป็น Mathematica!
DavidC

3

CJam - 37

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

ลองออนไลน์

คำอธิบาย:

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

หมายเหตุ:

  • ความซับซ้อนนั้นเกี่ยวกับ O (S * N) ดังนั้นมันจึงช้ามากสำหรับ S ขนาดใหญ่
  • CJam ขาดตัวดำเนินการทางคณิตศาสตร์อย่างมากสำหรับ 2 อาร์เรย์สิ่งที่ฉันวางแผนจะนำมาใช้ในภายหลัง

แนวคิดที่แตกต่าง - 46

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

ลองออนไลน์

นี่เป็นสิ่งที่ตรงไปตรงมาและมีประสิทธิภาพมากกว่า แต่อนิจจาค่อนข้างนานกว่าเล็กน้อย ความคิดที่นี่คือการเริ่มต้นด้วย L_i = floor (S * W_i) กำหนดความแตกต่าง (พูด D) ระหว่าง S กับผลรวมของพวกเขาค้นหาดัชนี D ที่มีส่วนที่ใหญ่ที่สุดของ S * W_i (โดยการเรียงลำดับและจด D) และเพิ่ม L_i สำหรับดัชนีเหล่านั้น ความซับซ้อน O (N * บันทึก (N))


ขณะนี้มีโอ :e<(N)
jimmy23013

@ user23013 โอ้ใช่แล้วสำหรับโปรแกรมแรกขอบคุณ
aditsu ออกเพราะ SE นั้นชั่วร้าย

มันเร็วมาก! ยินดีด้วย🌟
glebm

สำหรับผู้ที่สงสัยการแทนที่การเรียงลำดับด้วยอัลกอริธึมการเลือกเวลาแบบเชิงเส้นจะให้ O (n) แทน O (nlogn) จริงที่เกิดจากการเรียงลำดับ: ค้นหาองค์ประกอบที่ใหญ่ที่สุด D-th, P, O (N) จากนั้นเพิ่มขึ้น องค์ประกอบที่เป็น≥PD (O (N) ตั้งแต่ D <= N)
glebm

@glebm มันเจ๋ง แต่ฉันคิดว่ามีปัญหาถ้าองค์ประกอบหลายอย่างมีค่าเท่ากัน (P) บางทีคุณสามารถแก้มันใน 2 ผ่านแล้ว: เพิ่มครั้งแรกและนับองค์ประกอบ> P แล้วคุณรู้ว่าจำเป็นต้องมีองค์ประกอบ = P หรือถ้าคุณสามารถรับข้อมูลจากอัลกอริทึมการเลือกได้ดียิ่งขึ้น
aditsu ออกจากเพราะ SE นั้นชั่วร้าย

3

JavaScript (ES6) 126 130 104 115 156 162 194

หลังจากความคิดเห็นและกรณีทดสอบทั้งหมดในคำตอบของ @ CarpetPython กลับไปที่อัลกอริทึมแรกของฉัน อนิจจาโซลูชันอัจฉริยะไม่ทำงาน การใช้งานที่สั้นลงเล็กน้อยก็ยังคงพยายามแก้ปัญหาที่เป็นไปได้ทั้งหมดคำนวณระยะทางกำลังสองและรักษาค่าต่ำสุด

แก้ไขสำหรับแต่ละองค์ประกอบเอาต์พุตของน้ำหนัก w ค่าที่เป็นไปได้ 'ทั้งหมด' เป็นเพียง 2: trunc (w * s) และ trunc (w * s) +1 ดังนั้นจึงมีวิธีแก้ปัญหาที่เป็นไปได้เพียงแค่ (2 ** elemensts)

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

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

เอาท์พุต

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]

นั่นเป็นทางออกที่ฉลาดกว่า ผ่านเดียวในอาร์เรย์ weigth
สำหรับรหัสผ่านแต่ละครั้งฉันจะหาค่าสูงสุดในหน่วย ฉันเปลี่ยนค่านี้โดยใช้ค่าจำนวนเต็มถ่วงน้ำหนัก (ปัดขึ้น) ดังนั้นถ้า s == 21 และ w = 0.4 เราได้ 0.5 * 21 -> 10.5 -> 11 ฉันเก็บค่านี้เมื่อตะกี้ดังนั้นจึงไม่สามารถ พบได้สูงสุดในลูปถัดไป จากนั้นฉันก็ลดผลรวมทั้งหมดตามลำดับ (s = s-11) และยังลดผลรวมของ weigths ในตัวแปร f
การวนซ้ำจะสิ้นสุดลงเมื่อไม่พบสูงสุดที่ 0 (ค่าทั้งหมด! = 0 ได้รับการจัดการแล้ว)
ในที่สุดฉันก็กลับไปเปลี่ยนค่าเป็นบวกอีกครั้ง คำเตือนรหัสนี้จะแก้ไขอาเรย์ของน้ำหนักให้ถูกต้องดังนั้นจึงต้องเรียกใช้พร้อมกับสำเนาของอาเรย์ดั้งเดิม

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)

ความพยายามครั้งแรกของฉัน

ไม่ใช่โซลูชันที่ชาญฉลาด สำหรับผลลัพธ์ที่เป็นไปได้ทุกครั้งมันจะประเมินความแตกต่างและรักษาระดับต่ำสุดไว้

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และอธิบาย

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 ไบต์

วิธีแก้ปัญหาตรงไปตรงมา

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

อินพุตเหมือน

[0.3 0.4 0.3] 4

คำอธิบาย:

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

ลองออนไลน์ได้ที่นี่


2

Pyth: 40 ไบต์

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

สิ่งนี้นิยามฟังก์ชันgด้วยพารามิเตอร์ 2 ตัว Mhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4คุณสามารถเรียกมันเหมือน

ลองใช้งานออนไลน์: Pyth Compiler / Executor

คำอธิบาย:

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

นี้จะสร้างโซลูชั่นที่เป็นไปได้ทั้งหมดLที่หรือL[i] = floor(S*W[i]) L[i] = floor(S*W[i]+1)ยกตัวอย่างเช่นการป้อนข้อมูลที่สร้าง4 [0.3 0.4 0.3[[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

เหลือ[[2, 1, 1], [1, 2, 1], [1, 1, 2]]อยู่เท่านั้น

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}


คำอธิบาย

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]ผลตอบแทนที่ทุกพาร์ทิชันจำนวนเต็มของsใช้องค์ประกอบที่นำมาจากชุด{0, 1, 2, ...s}ที่มีข้อ จำกัด wว่าการส่งออกควรมีหมายเลขเดียวกันขององค์ประกอบในขณะที่ชุดของน้ำหนัก,

Permutations ให้การเตรียมการสั่งซื้อทั้งหมดของแต่ละพาร์ติชันจำนวนเต็ม

{Tr[(s *w-#)^2],#}ส่งคืนรายการคู่ที่สั่งซื้อ{error, permutation} สำหรับการเปลี่ยนแปลงแต่ละครั้ง

Sort[...] เรียงลำดับรายการของ {{error1, permutation1},{error2, permutation2}...according to the size of the error.

[[1,2]]]หรือส่งกลับรายการที่สองขององค์ประกอบแรกในรายการที่เรียงลำดับของPart[<list>,{1,2}] {{error, permutation}...}กล่าวอีกนัยหนึ่งมันคืนค่าการเปลี่ยนแปลงด้วยข้อผิดพลาดที่น้อยที่สุด


2

R, 85 80 76

ใช้วิธี Hare Quota

ลบคู่รักออกหลังจากเห็นสเป็คที่Wจะรวมเป็น 1

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

ทดสอบการทำงาน

> (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 ไบต์

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]

โซลูชัน itertools ก่อนหน้า 139 ไบต์

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]

ฉันสงสัยว่าโซลูชัน itertools จะเป็นไปได้หรือไม่ เป็นคนดี +1 ฉันคิดถูกไหมว่านี่มีความซับซ้อนของเวลา O (n ^ 4)?
Logic Knight

วิธีการแก้ปัญหา Itertools เป็นO(S^len(W))จริง: หน้า โซลูชั่นใหม่เร็วขึ้นมาก แต่ก็ยังช้า
Sp3000

2

อ็อกเทฟ, 87 76

แข็งแรงเล่นกอล์ฟ:

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

(ทำลาย "endfor" และ "endfunction"! ฉันจะไม่มีวันชนะ แต่ฉันสนุกกับการเล่นกอล์ฟด้วยภาษา "ของจริง")


อัลกอริทึมที่ดี คุณสามารถแทนที่ด้วยzeros(size(w)) 0*w
alephalpha

ดี! ทำไมฉันไม่คิดอย่างนั้น
dcsohl

1

T-SQL, 167 265

เพราะฉันชอบที่จะลองและทำสิ่งท้าทายเหล่านี้ในแบบสอบถามเช่นกัน

เปลี่ยนมันเป็นฟังก์ชั่นอินไลน์เพื่อให้เหมาะสมกับสเป็คที่ดีขึ้นและสร้างประเภทสำหรับข้อมูลตาราง มันเสียค่าใช้จ่ายเล็กน้อย แต่นี่ไม่เคยเป็นคู่แข่ง แต่ละคำสั่งจะต้องดำเนินการแยกกัน

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

ในการใช้งาน

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.