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
}