题目链锁:http://poj.org/problem?id=3071
题意:有2^n个队伍,进行n轮比赛,按编号顺序进行比赛,如第一支对第二支, 第三支对第四支……,给出队伍i打败队伍j的概率, 求胜率最高的那只队。
dp[i][j]表是第i轮第j队胜出,
第n轮获胜的队是由l = 1到r = 2^n 角逐出来的,那么判断j是在m=(l+r)/2左边还是右边,
如果在左边则dp[i][j] = dp[i-1][j] * d[i-1][k] * p[i][k] , m+1 <= k <= r;
如果在右边则dp[i][j] = dp[i-1][j] * d[i-1][k] * p[i][k] , l <= k <= m;
接着把l,r递归下去;
边界是i == 0 返回1
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
#define eps 1e-9
#define mod 10007
#define FOR(i,s,t) for(int i = s; i < t; ++i )
#define REP(i,s,t) for( int i = s; i <= t; ++i )
#define LL long long
#define ULL unsigned long long
#define pii pair<int,int>
#define MP make_pair
#define lson id << 1 , l , m
#define rson id << 1 | 1 , m + 1 , r
#define maxn ( 1000+10 )
#define maxe ( 20000+10 )
#define mxn 20000
double dp[10][maxn];
double p[maxn][maxn];
bool vis[11][maxn];
double DP ( int i, int j, int l, int r ) {
if( i == 0 ) return 1;
if( vis[i][j] ) return dp[i][j];
vis[i][j] = 1;
int m = l + r >> 1;
if( j <= m )
REP( k ,m+1, r )
dp[i][j] += DP( i-1, j, l , m ) * DP( i-1, k, m+1, r ) * p[j][k];
else
REP( k, l, m )
dp[i][j] += DP( i-1, j, m+1, r ) * DP( i-1, k, l, m ) * p[j][k];
return dp[i][j];
}
int main () {
int n;
while( ~scanf("%d", &n ) ) {
if( n == -1 ) break;
memset( vis,0, sizeof( vis ) );
memset( dp, 0, sizeof( dp ) ) ;
int m = ( 1 << n );
for( int i = 1; i <= m; ++i )
for ( int j = 1; j <= m; ++j )
scanf("%lf", &p[i][j] );
double mx = 0, ans;
int res;
for( int i = 1; i <= m; ++i ) {
ans = DP( n, i, 1, 1<<n );
if( ans > mx )
res = i, mx = ans;
}
//cout<<mx<<endl;
printf("%d\n", res );
}
}