QiQi and Bonds

只有链接: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)的了,否则会每次都会计算一次。这样就过了。一开始还不知道怎么枚举上一层的状态,结果是把总的每一种都枚举一遍。不错不错,继续努力。

最近看到一句话分享给大家:只有一条路不能选择---那就是放弃的的路;只有一条路不能拒绝---那就是成长的路!

 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\n",maxn);
56     }
57 }
View Code

 

posted on 2014-07-28 10:42  天依蓝  阅读(177)  评论(0编辑  收藏  举报

导航