http://poj.org/problem?id=3071
记忆化搜索
代码及其注释:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<map> #include<cmath> #define LL long long using namespace std; const int N=130; double win[N][N];//第几队 在第几次比赛中获胜的概率 double beat[N][N];// i赢j的概率 double pro(int k,int x,int l,int r)//第k队 第x次比赛 l和r用来确认范围 { if(win[k][x]>=0.0) return win[k][x];//记忆化 if(x==0) { win[k][x]=1.0;//第0次一定获胜 为边界 return win[k][x]; } int mid=(l+r)>>1; double ftemp=0.0; if(k<=mid)//判定k 所在的范围 和他的对手范围 { for(int i=mid+1;i<=r;++i) { ftemp+=(beat[k][i]*pro(i,x-1,mid+1,r));//累加 对手出现的概率和打败概率的乘积 } win[k][x]=pro(k,x-1,l,mid)*ftemp;//最后乘上自己出现的概率 }else { for(int i=l;i<=mid;++i) { ftemp+=(beat[k][i]*pro(i,x-1,l,mid)); } win[k][x]=pro(k,x-1,mid+1,r)*ftemp; } return win[k][x]; } int main() { int n; while(scanf("%d",&n)!=EOF) { if(n==-1) break; int m=int(pow(2,n)); for(int i=1;i<=m;++i) { for(int j=1;j<=m;++j) { scanf("%lf",&beat[i][j]); } } for(int i=1;i<=m;++i) { for(int j=0;j<=n;++j) { win[i][j]=-1.0;//初始化 } } int ans=1; for(int i=1;i<=m;++i) { if(pro(i,n,1,m)>win[ans][n])//枚举每队的获胜概率 记录最大的队伍 ans=i; } printf("%d\n",ans); } return 0; }