题意:火星的ACM比赛,一个队伍有若干名队员,每个题目只能一个小时由一个人完成,每个人对每个题目都有一个ac率,问最大的ac期望。限制是每一时刻任意两个人之间完成的题目数的差值不能超过1。
思路:一个比较简单的期望dp。因为每一时刻ac的题目数差距不能超过1,所以所有人都要同步ac题目,因为人数也不多,所以可以用位压缩来标识当前所有人题目完成情况,让没有完成题目的人去完成题目,那么dp[i][j | (1 << k)] = max(dp[i][j | (1 << k)], dp[i - 1][j] + pro[i][k]),前提是j&(1 << k)为0,即第k个人还没有完成题目。需要注意的是对于n个人,0和(1<<n)-1是一样的。
#include <cstdio>
#include <cstring>
inline double max(double a, double b){
return a > b ? a : b;
}
double dp[1010][1024], pro[12][1010];
main() {
int t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++) {
int n, m;
for(int i = 0; i < 1010; i++)
for(int j = 0; j <1024; j++)
dp[i][j] = -1;
dp[0][0] = 0.0;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
for(int j = 1; j <= m; j++)
scanf("%lf", &pro[i][j]);
/* for(int i = 0; i < n; i++) {
dp[0][1 << i] = pro[i][0];
}*/
int p = 1 << n;
for(int i = 0; i < m; i++) {
for(int j = 0; j < p; j++) {
if(dp[i][j] == -1) continue;
for(int k = 0; k < n; k++) {
if(j == p - 1) {
dp[i + 1][1 << k] = max(dp[i + 1][1 << k], dp[i][j] + pro[k][i + 1]);
// printf("%d %d %f\n", i, i << k, dp[i + 1][1 << k]);
}
if((1 << k) & j) continue;
dp[i + 1][j | (1 << k)] = max(dp[i + 1][j | (1 << k)], dp[i][j] + pro[k][i + 1]);
// printf("%d %d %f\n", i + 1, j | (1 << k), dp[i + 1][j | (1 << k)]);
}
}
}
double ans = 0;
for(int i = 0; i < p; i++) ans = max(ans, dp[m][i]);
printf("Case #%d: %.5f\n", cas, ans);
}
}