概率dp poj 3071

题目首先给出一个n,表示比赛一共进行n轮,那么队伍就有2^n只队伍
输入一个2^n*2^n的矩阵,p[i][j]代表队伍i打败队伍j的概率
dp[i][j]代表第i轮比赛的时候,队伍j赢的概率
首先初始化时,dp[0][i]=1,在没有比赛时每个队伍都是赢的
dp[i][j]+=dp[i-1]j[*dp[i-1][k]*p[j][k]:要求j和k的上一轮都是赢家的概率再乘以本轮j打败k的概率
特别注意,队伍只能相邻的打,相邻的队伍转换成二进制时,高位相同,到第i位正好相反
可以用 if(((j>>(i-1))^1)==(k>>(i-1)))来判断,是否相邻,或者是下面代码中我所用的方法
因为最开始一轮两两相邻的打,只有二进制中的最后一位不一样,第二轮时,上一轮的赢家相邻的打,是第二位不一样
很巧妙

————————————————
版权声明:本文为CSDN博主「Cherry_0525」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41037114/article/details/81906416

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<string.h>
 4 #include<math.h>
 5 using namespace std;
 6 const int maxn=1<<8;
 7 double p[maxn][maxn];
 8 double dp[maxn][maxn];
 9 int main()
10 {
11     int n;
12     while(scanf("%d",&n)!=EOF){
13         if(n==-1) break;
14         int len=1<<n;
15         for(int i=1;i<=len;i++)
16         for(int j=1;j<=len;j++){
17             scanf("%lf",&p[i][j]);
18         }
19         memset(dp,0,sizeof(dp));
20         for(int i=1;i<=len;i++) dp[0][i]=1.0;
21         for(int i=1;i<=n;i++){
22             for(int j=1;j<=len;j++)
23             for(int k=1;k<=len;k++){
24                 if((((j-1)>>(i-1))^1)==((k-1)>>(i-1)))   //这是一个判断相邻的操作。
25                     dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];
26 
27             }
28         }
29         double mx=0.0;
30         int ansbase=0;
31         for(int i=1;i<=len;i++)
32         if(dp[n][i]>mx){
33             mx=dp[n][i];
34             ansbase=i;
35         }
36         printf("%d\n",ansbase);
37     }
38     return 0;
39 }

 

posted @ 2019-09-24 23:18  古比  阅读(137)  评论(0编辑  收藏  举报