这个题是一个DP。 有状态压缩的问题。 以前只是听说过 状态压缩的DP 还没有真正练过。 今天还好把这个题弄明白了
其中有一个条件就是不论什么时候。 任何两个人的做题时间之差不能超过2. 那个这个条件的另一个意思也就是说。 必须所有人都做一遍之后 再所有人再做一遍 这样循环
用 d【i】【j】 表示 前 i个题 都有 哪几个人做了。j是用二进制表示。 比如 i为2 j为 101000 就表示 前两个题 被 第一个人 和第三个人 做了的概率。
当所有人都做了一遍的时候 即 11111 这样的时候 j 再转为 0 再重新 找人。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <fstream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <list>
#include <vector>
#include <cmath>
#include <iomanip>
typedef long long LL;
typedef unsigned long long LLU;
const double PI=acos(-1.0);
using namespace std;
#define MAXN 1200
double peo[15][MAXN];
double d[MAXN][MAXN];
int main (){
int t;
int kase = 0;
scanf("%d",&t);
while(t--){
int pe,con;
scanf("%d%d",&pe,&con);
for(int i = 0; i < pe; i++)
for(int j = 0; j < con; j++)
scanf("%lf",&peo[i][j]);
for(int i = 0; i < MAXN; i++){
for(int j = 0; j < MAXN; j++)
d[i][j] = -1;
}
d[0][0] = 0;
for(int i = 0; i < con; i++){
for(int j = 0; j < (1 << pe); j++){
int s;
if(d[i][j] < 0)
continue;
for(int k = 0; k < pe; k++){
if(!((1 << k) & j)){ // 第k个人没做过题
s = ((1 << k) | j);
if(s == (1 << pe) - 1)
s = 0; // 所有人都做过了一遍 重新做
d[i+1][s] = max(d[i+1][s], d[i][j] + peo[k][i]);
// printf("%lf\n",d[i+1][s]);
}
}
}
}
double ans = 0.0;
printf("Case #%d: ",++kase);
for(int i = 0; i < (1 << pe); i++)
ans = max(ans, d[con][i]);
printf("%.5lf\n",ans);
}
return 0;
}