只有链接:http://sdu.acmclub.com/index.php?app=problem_title&id=961&problem_id=23685
题意:现在有n个QiQi和n个任务,告诉了每个QiQi能够成功完成这n个任务的概率,每个QiQi只能完成一种任务,问你如何安排任务使得所有的任务被完成的概率最大。
题解:很明显的状压Dp啊。之前没有独立的打过这种DP,比赛的时候打了一发,结果WA,第二天才知道自己枚举的时候状态少枚举了。结果复习了一下状压dp。然后打了一发,结果T了。然后就想优化。发现,对于第i行来说,枚举i-1行的时候,这时候室友优化的,因为前i-1行所放的东西的个数必须是i-1个,结果改了,加了一个判断,结果还T了,想了想,其实还是可以优化的,就是判断的时候可以事先把每一种状态的1的个数处理处理,那么判断的时候就可以O(1)的了,否则会每次都会计算一次。这样就过了。一开始还不知道怎么枚举上一层的状态,结果是把总的每一种都枚举一遍。不错不错,继续努力。
最近看到一句话分享给大家:只有一条路不能选择---那就是放弃的的路;只有一条路不能拒绝---那就是成长的路!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 double dp[2][(1<<20)]; 7 double a[23][23]; 8 int c[1<<20]; 9 int n; 10 int counts(int x){ 11 int ans=0; 12 while(x){ 13 ans+=(x&1); 14 x/=2; 15 } 16 return ans; 17 } 18 void solve(){ 19 memset(c,0,sizeof(c)); 20 for(int i=1;i<(1<<n);i++){ 21 c[i]=counts(i); 22 } 23 } 24 int main(){ 25 while(~scanf("%d",&n)){ 26 memset(dp,0,sizeof(dp)); 27 memset(a,0,sizeof(a)); 28 solve(); 29 for(int i=1;i<=n;i++) 30 for(int j=1;j<=n;j++) 31 scanf("%lf",&a[i][j]); 32 33 for(int i=1;i<=n;i++) 34 dp[1][1<<(i-1)]=a[1][i]; 35 36 for(int i=2;i<=n;i++){ 37 memset(dp[i&1],0,sizeof(dp[i&1])); 38 for(int j=1;j<(1<<n);j++){ 39 if(c[j]!=i-1)continue; 40 for(int k=1;k<=n;k++){ 41 int temp=(1<<(k-1)); 42 if(!(temp&j)){ 43 dp[i&1][temp+j]=max(dp[i&1][temp+j],dp[(i-1)&1][j]*a[i][k]); 44 } 45 } 46 } 47 } 48 double maxn=0; 49 for(int i=1;i<(1<<n);i++){ 50 maxn=max(maxn,dp[n&1][i]); 51 } 52 for(int i=1;i<n;i++){ 53 maxn/=100.0; 54 } 55 printf("%.6lf ",maxn); 56 } 57 }