【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 }