题目链接
http://poj.org/problem?id=3071
思路
概率DP,方程本身很简单,设dp[i][j]
为第i支队伍撑过第j轮的概率。
则对第j轮i所有的可能对手k,dp[i][j]+=dp[i][j-1]*dp[k][j-1]*p[i][k]
。
但是难点就是怎么找出可能对手k,上网搜了下发现可以巧妙的用二进制搞定。
把ijk都从0开始编号,那么在第j轮,i和k可能是对手当且仅当i和k的第(j+1)位相反且最高位相同。
即:((k>>j)^1)==(i>>j)
。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
double dp[200][10];
double p[200][200];
int main()
{
int n;
while(scanf("%d",&n),n!=-1)
{
int n_team=(1<<n);
for(int i=0 ; i<n_team ; ++i)
for(int j=0 ; j<n_team ; ++j)
scanf("%lf",&p[i][j]);
memset(dp,0,sizeof dp);
for(int i=0 ; i<n_team ; i+=2)
{
dp[i][0]=p[i][i+1];
dp[i+1][0]=p[i+1][i];
}
for(int j=1 ; j<n ; ++j)
{
for(int i=0 ; i<n_team ; ++i)
{
for(int k=0 ; k<n_team ; ++k)
if(((k>>j)^1)==(i>>j))
{
dp[i][j]+=dp[i][j-1]*dp[k][j-1]*p[i][k];
}
}
}
double max_p=dp[0][n-1];
int max_i=0;
for(int i=1 ; i<n_team ; ++i)
{
if(dp[i][n-1]>max_p)
{
max_p=dp[i][n-1];
max_i=i;
}
}
printf("%d\n",max_i+1);
}
return 0;
}