【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 }
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 糊涂啊!这个需求居然没想到用时间轮来解决
· 浅谈为什么我讨厌分布式事务
· 在 .NET 中使用内存映射文件构建高性能的进程间通信队列
· 一个 java 空指针异常的解决过程
· 干翻 Typora!MilkUp:完全免费的桌面端 Markdown 编辑器!
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 从WebApi迁移到Minimal API?有了这个神器,小白也能10分钟搞定!
· 那些年我们一起追过的Java技术,现在真的别再追了!
· 抛开官方库,手撸一个轻量级 MCP 服务端