2 n 2^n 2n支球队,进行 n n n场比赛
对于每场比赛,存活下来的队伍按照编号递增的顺序站成一排
第一支队伍和第二支打,第三支队伍和第四支队伍打…一此类推
n n n场比赛后只有一个队伍会取胜,你只需要输出最可能获得胜利的那支队伍即可。
定义 f [ i ] [ j ] f[i][j] f[i][j]表示第 i i i轮第 j j j个人存活下来的概率
设 j j j在这一轮可能和 x 1 , x 2 . . . x k x_1,x_2...x_k x1,x2...xk打
f [ i ] [ j ] = 1 k ∗ ∑ l = 1 k f [ x l ] [ j − 1 ] f[i][j]=\frac{1}k{}*\sum\limits_{l=1}^{k}f[x_l][j-1] f[i][j]=k1∗l=1∑kf[xl][j−1]
但是这一轮,第 j j j个人要和哪些队伍打…
↗ ↖
* *
↗ ↖ ↗↖
* * * *
↗↖ ↗↖ ↗↖ ↗↖
0 1 2 3 4 5 6 7
第 i i i轮第 j j j个人决斗的目标
110 111
就是从下往上第 i + 1 i+1 i+1层的根节点另一侧的所有节点
所以我们只需要判断每个节点在左侧还是右侧即可
所以把节点编号左移 i − 1 i-1 i−1位,那么第 i i i位的二进制 0 / 1 0/1 0/1代表左右侧
除了这一位,其他位都需要相等
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1009;
int n;
double f[maxn][maxn],p[maxn][maxn];
int main()
{
while( cin >> n&&n!=-1 )
{
int mx = (1<<n);
for(int i=0;i<mx;i++)
for(int j=0;j<mx;j++)
cin >> p[i][j];
for(int i=0;i<mx;i++) f[0][i] = 1;
for(int i=1;i<=n;i++)
for(int j=0;j<mx;j++)
{
f[i][j] = 0;
for(int k=0;k<mx;k++)
{
if( ((j>>(i-1))^1)==(k>>(i-1)) )
f[i][j] += f[i-1][j]*f[i-1][k]*p[j][k];
}
}
double maxx = f[n][0];
int index = 0;
for(int i=1;i<mx;i++)
if( f[n][i]>maxx ) maxx = f[n][i],index = i;
cout << index+1 << endl;
}
}