题目链接:http://poj.org/problem?id=3071
解题思路:
题目意思比较简单,就是已知1<<n个队伍,每两个队伍比赛的获胜概率,比赛的规则是相邻的两个队伍进行比赛,输的直接淘汰,赢得继续,求哪个队伍获胜的概率最大。
所谓的相邻就是1和2 3和4 5和6 ....1和2打,如果1赢了,1再继续和3,4中的赢家比一次,这样,最后的赢家就打了n场比赛。
用dp[ i ][ j ]表示第i次比赛,j赢得概率。
那么递推方程就是dp[ i ][ j ]+=dp[ i-1 ][ j ]*dp[ i-1 ][ k ]*p[ j ][ k ];第i场比赛如果是j赢了,那么第i-1场j也是赢家,第i场比赛j应该和第i-1场的另一个相邻的赢家k比,且在第i场中j胜了,即p[ j ][ k ]
那么剩下的一个问题就是k是谁?
将1~(1<<n)个队伍编号为0~(1<<n-1),假设n=3
第一场比赛:
00 vs 01
10 vs 11
100 vs 101
110 vs 111
在第一场比赛队伍的二进制右起第0位是相反的(位数从零开始)
假设第一场中 胜利的是00、11、101、111,那么
第二场比赛
00 vs 11
101 vs 111
在这一场比赛中,参赛队伍的二进制右起第1位是相反的
此时大致的规律已经出来了,我们不妨再验证一下
假设第二场比赛胜利的是11、101,那么
第三场比赛
11 vs 101
参赛队伍二进制右起第2位是相反的
总的来说就应该是第i场比赛,参赛队伍二进制右起第i位是相反的,利用这一点我们就可以很好的确定k究竟是哪一个。
(j>>(i-1)^1)==(k>>(i-1)) 表示的是对 j 的二进制(i-1)位取反与 k 的二进制的(i-1)位相比较
( 1^1=0 , 0^1=1 )
#include <iostream>
#include <string.h>
using namespace std;
double p[1<<7+1][1<<7+1],dp[8][1<<7+1];
int main()
{
int n;
while(cin>>n && n!=-1)
{
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<(1<<n);j++)
{
cin>>p[i][j];
}
}
memset(dp,0,sizeof(dp));
for(int i=0;i<(1<<n);i++)
dp[0][i] = 1;//第0场比赛时,每队赢的概率都是1
for(int i= 1;i<=n;i++)//打了n场比赛
{
for(int j=0;j<(1<<n);j++)
{
for(int k = 0;k<(1<<n);k++)
{
if((j>>(i-1)^1)==(k>>(i-1)))
dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];
}
}
}
double ans = -1;
int k;
for(int i=0;i<(1<<n);i++)
{
if(ans<dp[n][i])
{
ans = dp[n][i];
k = i;
}
}
cout<<k+1<<endl;
}
return 0;
}
527

被折叠的 条评论
为什么被折叠?



