题意:
有2^n个队伍要进行足球比赛。问你最终哪个队伍胜出的几率最大。
输出该队伍。
思路:
由于队伍只能和它当前所能企及的一些队伍进行比赛,因此我想了一下类似线段树那样二分一下位置。
如果一个队伍赢了n场,那它就胜出。
dp[i][j]:第i个队伍,赢了j场比赛的概率。
转移:简单来说,dp[i][j]就是dp[i][j-1] 乘以另外旁系也赢了j-1场的队伍,别忘了把赢的概率也乘上。
貌似用dfs记忆化搜索比较好理解。
code:
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 150;
const int MAXM = 10;
double dp[MAXN][MAXM];
double a[MAXN][MAXN];
double dfs(int l, int r, int u, int ti)
{
if(dp[u][ti] != -1) return dp[u][ti];
int mid = (l+r)/2;
double tmp = 0;
if(u > mid)
{
dp[u][ti] = dfs(mid+1, r, u, ti-1);
for(int i = l; i <= mid; i++)
tmp += a[u][i] * dfs(l, mid, i, ti-1);
}
else
{
dp[u][ti] = dfs(l, mid, u, ti-1);
for(int i = mid+1;i <= r; i++)
tmp += a[u][i] * dfs(mid+1, r, i, ti-1);
}
return dp[u][ti] *= tmp;
}
int main()
{
int n;
while(scanf("%d" ,&n) != EOF)
{
if(n == -1) break;
int nn = 1<<n;
for(int i = 0;i < nn; i++)
for(int j = 0;j < nn; j++)
scanf("%lf", &a[i][j]);
for(int i = 0;i < nn; i++)
for(int j = 0;j <= n; j++)
dp[i][j] = -1;
for(int i = 0;i < nn; i++)
dp[i][1] = a[i][i^1];
for(int i = 0;i < nn; i++)
dfs(0, nn-1, i, n);
double res = -1;
int idx = 0;
for(int i = 0;i < nn; i++)
{
//cout<<dp[i][n]<<endl;
if(res < dp[i][n])
res = dp[i][n], idx = i;
}
printf("%d\n", idx+1);
}
return 0;
}