【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  阅读(152)  评论(0)    收藏  举报
编辑推荐:
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 糊涂啊!这个需求居然没想到用时间轮来解决
· 浅谈为什么我讨厌分布式事务
· 在 .NET 中使用内存映射文件构建高性能的进程间通信队列
· 一个 java 空指针异常的解决过程
阅读排行:
· 干翻 Typora!MilkUp:完全免费的桌面端 Markdown 编辑器!
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 从WebApi迁移到Minimal API?有了这个神器,小白也能10分钟搞定!
· 那些年我们一起追过的Java技术,现在真的别再追了!
· 抛开官方库,手撸一个轻量级 MCP 服务端
点击右上角即可分享
微信分享提示