一个足球比赛有2^n个队伍参加。比赛按照队伍编号进行。1和2比、3和4比、5和6比...比完后1,2的胜利队伍和3,4的胜利队伍比...以此类推,知道最后只剩下一只队伍成为胜利者。
现在给出 n 和一个二维数组P,P[i][j] 表示编号 i 的队伍战胜编号为 j 的队伍的概率。
求最有可能成为获胜者的队伍编号。
观察题目我们可以发现比赛赛程是棵二叉树。所以我们可以利用树的结构解题。树的每个节点都表述队伍编号的一段区间我们要求的是该区间的每个队伍一路获胜并且到达该节点的
概率。
dp[t][i] : 表示t节点上编号为 i 的队伍获胜的概率。则 i号队伍必须在其所在的子树区间获胜,并打败另一个字树区间的获胜队伍。
dp[t][i] = dp[t1][i] * Σ(dp[t2][j] * p[i][j]);
但是明显这样表示的转移方程比较麻烦。我提供另一种思路。如果i号队伍在左子树区间获胜,j号队伍在右子树区间获胜,i战胜j则i在当前节点获胜。反之同理。
dp[t][i] += dp[t_l][i] * dp[t_r][j] * p[i][j];
dp[t][j] += dp[t_l][i] * dp[t_r][j] * p[j][i];
现在给出 n 和一个二维数组P,P[i][j] 表示编号 i 的队伍战胜编号为 j 的队伍的概率。
求最有可能成为获胜者的队伍编号。
观察题目我们可以发现比赛赛程是棵二叉树。所以我们可以利用树的结构解题。树的每个节点都表述队伍编号的一段区间我们要求的是该区间的每个队伍一路获胜并且到达该节点的
概率。
dp[t][i] : 表示t节点上编号为 i 的队伍获胜的概率。则 i号队伍必须在其所在的子树区间获胜,并打败另一个字树区间的获胜队伍。
dp[t][i] = dp[t1][i] * Σ(dp[t2][j] * p[i][j]);
但是明显这样表示的转移方程比较麻烦。我提供另一种思路。如果i号队伍在左子树区间获胜,j号队伍在右子树区间获胜,i战胜j则i在当前节点获胜。反之同理。
dp[t][i] += dp[t_l][i] * dp[t_r][j] * p[i][j];
dp[t][j] += dp[t_l][i] * dp[t_r][j] * p[j][i];
写代码的时候可以套用线段树的结构。
/***********************************************
** problem ID : poj_3071.cpp
** create time : Mon Jul 27 21:18:44 2015
** auther name : xuelanghu
** auther blog : blog.csdn.net/xuelanghu407
**********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
// dp[t][i] += p[i][j] * dp[tl][i] * dp[tr][j];
// dp[t][j] += p[j][i] * dp[tl][i] * dp[tr][j];
int n;
double p[(1<<7)+5][(1<<7)+5];
struct Node {
double p[(1<<7) + 5];
}dp[(1<<10)];
void DP(int l, int r, int lr) {// cout<< lr << endl;getchar();
if (l == r) {
dp[lr].p[l] = 1.0;
return ;
}
int mid = (l + r) >> 1;
DP(l, mid, lr<<1);
DP(mid+1, r, lr<<1|1);
for (int i=l; i<=mid; i++) {
for (int j=mid+1; j<=r; j++) {
dp[lr].p[i] += p[i][j] * dp[lr<<1].p[i] * dp[lr<<1|1].p[j];
dp[lr].p[j] += p[j][i] * dp[lr<<1].p[i] * dp[lr<<1|1].p[j];
}
}
}
int main () {
while (cin >> n) {
if (n == -1) break;
memset(dp, 0, sizeof(dp));
for (int i=1; i<=(1<<n); i++) {
for (int j=1; j<=(1<<n); j++) {
cin >> p[i][j];
}
}
DP(1, 1<<n, 1);
double ans = 0.0;
int pos = 0;
for (int i=1; i<=(1<<n); i++) {
if (ans < dp[1].p[i]) {
ans = dp[1].p[i];
pos = i;
}
}
cout << pos << endl;
}
return 0;
}