JavaScript (ES6) 126 130 104 115 156 162 194
Sau tất cả các nhận xét và trường hợp thử nghiệm trong câu trả lời của @ RugPython, hãy quay lại thuật toán đầu tiên của tôi. Than ôi, giải pháp thông minh không hoạt động. Việc thực hiện rút ngắn một chút, nó vẫn cố gắng tất cả các giải pháp có thể, tính khoảng cách bình phương và giữ mức tối thiểu.
Chỉnh sửa Đối với mỗi phần tử đầu ra của trọng số w, 'tất cả' các giá trị có thể chỉ là 2: trunc (w * s) và trunc (w * s) +1, do đó, chỉ có (2 ** elemensts) có thể thử các giải pháp.
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
Kiểm tra trong bảng điều khiển 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])))
Đầu ra
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]
Đó là một giải pháp thông minh hơn. Vượt qua duy nhất trên mảng weigth.
Đối với mỗi lần vượt qua tôi tìm giá trị tối đa hiện tại trong w. Tôi thay đổi giá trị này tại chỗ bằng giá trị nguyên có trọng số (làm tròn lên), vì vậy nếu s == 21 và w = 0,4, chúng tôi nhận được 0,5 * 21 -> 10,5 -> 11. Tôi lưu trữ giá trị này bị phủ định, vì vậy không thể được tìm thấy tối đa trong vòng lặp tiếp theo. Sau đó, tôi giảm tổng tổng tương ứng (s = s-11) và cũng giảm tổng số các biến trong biến f.
Vòng lặp kết thúc khi không tìm thấy tối đa trên 0 (tất cả các giá trị! = 0 đã được quản lý).
Cuối cùng, tôi trả lại các giá trị thay đổi thành tích cực.
Cảnh báo mã này sửa đổi mảng trọng số tại chỗ, vì vậy nó phải được gọi bằng một bản sao của mảng gốc
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)
Lần thử đầu tiên của tôi
Không phải là một giải pháp thông minh. Đối với mọi kết quả có thể, nó đánh giá sự khác biệt và giữ mức tối thiểu.
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 và giải thích
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
}