E题:Lucky bag
标签:贪心、随机化
题意:给你
n
n
n件物品,第
i
i
i件物品的权重为
w
i
w_i
wi,想要把这些物品分成
d
d
d组,希望最小化总重量的方差。
方差定义:
V
=
1
D
∑
i
=
1
D
(
x
i
−
x
ˉ
)
2
V=\frac{1}{D}\displaystyle\sum_{i=1}^D (x_i-\bar{x})^2
V=D1i=1∑D(xi−xˉ)2,
x
ˉ
\bar{x}
xˉ定义为各组数据和的平局值:
x
ˉ
=
1
D
(
x
1
+
x
2
+
⋯
+
x
D
)
\bar{x}=\frac{1}{D}(x_1+x_2+\cdots+x_D)
xˉ=D1(x1+x2+⋯+xD)
题解: 通过观察能发现这是一个贪心,当
x
i
x_i
xi的值越接近答案越小, 我们可以把每个数加到当前和最小的组里,然后通过随机化 进行多次贪心,随机化的次数可以稍微多点。每次贪心把序列打乱, 然后多次进行操作获得对应的值,从中取最小值就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
int n, d, w[20], b[20], t = 2000000;
double ans = 1e18, sum = 0;
int main() {
cin >> n >> d;
for (int i = 1; i <= n; i++) {
cin >> w[i];
sum += w[i];
}
double avg = sum / d;
while (t--) {
memset(b, 0, sizeof(b));
random_shuffle(w + 1, w + n + 1);
int k = 1;
sum = 0;
for (int j = 1; j <= n; j++) {
for (int i = 2; i <= d; i++) {
if (b[i] < b[k]) k = i;
}
b[k] += w[j];
k = 1;
}
for (int i = 1; i <= d; i++) sum += (avg - b[i]) * (avg - b[i]);
sum = sum / d;
ans = min(ans, 1.0 * sum);
}
printf("%.15lf", ans);
return 0;
}