【POJ】【3071】Football

概率DP

  kuangbin总结中的第10题

  简单的画个比赛图,会发现是一颗完全二叉树,且同一层的子树之间各自独立,只有在合并得到更高一层结果时才结合。

  所以我们可以按比赛轮数进行DP,f[i][j]表示第 i 轮之后第 j 个球队没有被淘汰的概率,仔细一想可以发现:首先这支球队得在第 i-1 轮中胜出,然后他在第 i 轮中的对手的可能情况即是在比赛图二叉树中的「兄弟」结点代表的那2^(i-1)支球队,这个“兄弟”可以用异或快速求出。

  这样逐层递推,避免了许多无用的状态枚举,每层要枚举 2^i 支球队,以及第 i 支球队的2^(i-1)个可能的对手,所以复杂度为O(n* 2^2n)

 1 //POJ 3071
 2 #include<cmath>
 3 #include<cstdio>
 4 #define rep(i,n) for(int i=0;i<n;++i)
 5 #define F(i,j,n) for(int i=j;i<=n;++i)
 6 const int N=1<<8;
 7 double p[N][N],f[8][N];
 8 int main(){
 9 #ifndef ONLINE_JUDGE
10     freopen("3071.in","r",stdin);
11     freopen("3071.out","w",stdout);
12 #endif
13     int n,m;
14     while(scanf("%d",&n)!=EOF && n!=-1){
15         m=1<<n;
16         rep(i,m) rep(j,m) scanf("%lf",&p[i][j]);
17         
18         rep(j,m) f[0][j]=1.0;
19         F(i,1,n) rep(j,m){
20             int t=j/(1<<(i-1));
21             t^=1;
22             f[i][j]=0;
23             for(int k=t*(1<<(i-1)); k<t*(1<<(i-1))+(1<<(i-1));k++)
24                 f[i][j]+=f[i-1][j]*f[i-1][k]*p[j][k];
25         }
26         int ans;
27         double tmp=0;
28         rep(i,m)
29             if (f[n][i]>tmp){
30                 ans=i;
31                 tmp=f[n][i];
32             }
33         printf("%d\n",ans+1);
34     }
35     return 0;
36 }
View Code

 

posted @ 2015-02-26 22:28  Tunix  阅读(150)  评论(0编辑  收藏  举报