题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=68677#problem/D
题意:
将n个概率分成w组,使得期望值最小.
例如概率分别是 c1,c2,c3,c4,c5 把他们分成两组,G1 = {c1,c2,c2},G2 = {c4,c5} . 则 P = 3*(c1+c2+c3) + (3+2) * (c4+c5);
思路:
先将概率从大到小排序,然后求出前缀和.
DP状态转移方程是: dp[i][j] = min(dp[i[[j], dp[k-1][j-1] + i*(sum[i]-sum[k-1]) 表示前i个数分成j组的最小期望.
AC.
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int a[105], dp[105][105], sum[105];
int n, w;
bool cmp(double x, double y)
{
return x > y;
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
memset(sum, 0, sizeof(sum));
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = 0;
scanf("%d %d", &n, &w);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
sort(a+1, a+n+1, cmp);
sum[0] = 0;
for(int i = 1; i <= n; ++i) {
sum[i] = sum[i-1] + a[i];
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= w; ++j) {
for(int k = 1; k <= i; ++k) {
dp[i][j] = min(dp[i][j], dp[k-1][j-1]+i*(sum[i]-sum[k-1]));
}
}
}
printf("%.4lf\n", (double)dp[n][w]/sum[n]);
}
return 0;
}