//528K 94MS G++
#include <cstdio>
#include <cstring>
#include <cmath>
const int MAX = 130;
double P[MAX][MAX];
double DP[MAX][9];
int N;
int teamNum;
void getVSId(int curTeamId, int winTime, int & beginVSId, int & endVsId) {
int teamMemberCapcity = pow(2, winTime);
beginVSId = 1;
endVsId = beginVSId + teamMemberCapcity - 1;
while(1) {
if (curTeamId >= beginVSId && curTeamId <= endVsId) {
break;
} else {
beginVSId = endVsId + 1;
endVsId = beginVSId + teamMemberCapcity - 1;
}
}
int middleId = (beginVSId + endVsId)>>1;
if (curTeamId <= middleId) {
beginVSId = middleId+1;
} else {
endVsId = middleId;
}
// printf("getVSId %d %d %d %d\n", curTeamId, winTime, beginVSId, endVsId);
}
void beginDP() {
for (int winTime = 1; winTime <= N; winTime++) {
for (int teamId = 1; teamId <= teamNum; teamId++) {
if (winTime == 1) {
if (teamId%2) { // is odd, VS teamId +1
DP[teamId][1] = P[teamId][teamId+1];
} else { // is even, VS teamId -1
DP[teamId][1] = P[teamId][teamId-1];
}
// printf("DP %d %d %lf\n", teamId, 1, DP[teamId][1]);
} else {
int beginVSId;
int endVsId;
getVSId(teamId, winTime, beginVSId, endVsId);
double tmp = 0.0;
for (int i = beginVSId; i <= endVsId; i++) {
tmp += DP[i][winTime-1]*P[teamId][i];
// // printf("%lf %lf %lf %lf\n",
// // DP[i][winTime-1], P[teamId][i],
// DP[i][winTime-1]*P[teamId][i], tmp);
}
DP[teamId][winTime] = tmp*DP[teamId][winTime-1];
// printf("DP %d %d %lf %d %d\n", teamId, winTime, DP[teamId][winTime], beginVSId, endVsId);
}
}
}
}
void getMostPossibleWinner() {
beginDP();
int winnerId = 0;
double maxP = 0.0;
for (int i = 1; i<= teamNum; i++) {
if (maxP < DP[i][N]) {
maxP = DP[i][N];
winnerId = i;
}
}
// printf("%d %lf\n", winnerId, maxP);
printf("%d\n", winnerId);
}
int main() {
while(scanf("%d", &N) != EOF) {
if (N == -1) {
return 0;
}
teamNum = pow(2, N);
memset(P, 0, sizeof(P));
memset(DP, 0, sizeof(DP));
for (int i = 1; i <= teamNum; ++i) {
for (int j = 1; j <= teamNum; ++j) {
double Pij;
scanf("%lf", &Pij);
P[i][j] = Pij;
}
}
getMostPossibleWinner();
}
}
披着概率外衣的DP基础题,在写getVsID时犯了个低级错误.
题目咋一看比较唬人,不过结合着例子分析一下,DP的关系就出来了:
首先,题目指明了,比赛的对手安排:
1对2, 3对4 ...... N-1对N.
那么,对于1来说,赢一场的概率就是 P(1,2)(1击败2的概率)
而对于第二轮比赛,按照题目的规定,
1的选手只能是 3或者4,那么赢得概率就是 P(1,2)( P(1,3)*P(3,4) + P(1,4)*P(4,3) )
就这样递推,会发现,
某个选手i, 赢得N场比赛的概率DP[i][N]可以这样表示:
DP[i][N-1] (DP[A1][N-1]P(i,A1) + DP[A2][N-1]P(i,A3) + ... + DP[AN][N-1]P(i,AN))(A1... AN是 i在第N场比赛中可能遭遇的对手),
那么如何确定A1....AN, 可以观察发现:
对于1来说,第一场比赛的对手只可能是2,
第二场比赛的对手只可能是 3, 4
第三场比赛的对手只可能是 5 6 7 8
.......
可以发现,对于某个选手i来说,在第N轮比赛中,他是从一个规模为2的N-1次方的团体中脱颖而出的,而与之相对的也是一个2的N-1次方大小的团队,
这个团队的所有对手都可能会成为i 在第N轮比赛的对手。(对于该团队某个人 j, 能和i比赛的概率就是在此团队胜出的概率,就是DP[j][N-1])
getVsId就是求出与i在第N轮比赛中可能比赛的对手的序号范围,步骤也很简单,
对于第N论比赛,
i 脱颖而出的团队 和 可能做i对手的团队 会一起组成一个 连续 的 2的N次方大小的团队,
先确定这个团队T的范围,然后确定i是在T的前半部分(那么对手就在后半部分),还是后半部分(那么对手就在前半部分)。
最后利用上面的DP递推方程求出即可.