题目大意:
在一次单淘汰制的足球锦标赛中共有2^n个队伍参赛,编号依次为1, 2, 3....2^n(1 ≤ n ≤ 7),第一轮1打2、3打4...2^n-1打2^n,输者直接被淘汰,第二轮(1, 2)胜者打(3, 4)胜者....,依次类推,知道最后决出冠军。
现有多个测例,每个测例中给定n,以及一个2^n × 2^n的矩阵p,里面都是浮点数,p[i][j]表示i对赢j队的概率,现要求输出最终获胜率最大的球队的序号(都以double表示,以防止精度不够),以n = -1表示输入结束。
注释代码:
/*
* Problem ID : POJ 3071 Football
* Author : Lirx.t.Una
* Language : C
* Run Time : 79 ms
* Run Memory : 284 KB
*/
#include <stdio.h>
//maximum number of teams
//参赛队伍的最大数量
#define MAXTEAMN 128
//maximum number of rounds
//最多有几轮比赛
//可证明如果有2^n个参赛队伍则有n轮比赛
//总共7轮,从下标1开始计算因此取8
#define MAXROUNDN 8
//winning propability
//wp[i][j]表示i队赢j队的概率
double wp[MAXTEAMN][MAXTEAMN];
//dp[i][j]表示i队在第j轮比赛中获胜的概率
double dp[MAXTEAMN][MAXROUNDN];
//!!!注意:队伍从下标0开始计,比赛轮数从1计
//方便后面的按位或操作筛选队伍的对手
int
main() {
int rd;//round number,总比赛轮数
int tm;//team number,队伍数,从0计
int p;//player,当前参赛队伍
int op;//opponent player,当前参赛队伍的对手
int r;//round,当前处于第几轮
double tmp;//临时变量
int ans;
int i, j;//计数变量
int f;//筛选因子,用于筛选当前队伍的对手
while ( scanf("%d", &rd), rd != -1 ) {
tm = 1 << rd;
for ( i = 0; i < tm; i++ ) {
for ( j = 0; j < tm; j++ )
scanf("%lf", &wp[i][j]);
dp[i][0] = 1.0;//假设各队伍在第0轮中必定出现,因此概率为1
}
for ( r = 1; r <= rd; r++ )
for ( p = 0; p < tm; p++ ) {
//状态转移方程描述:
//p在当前轮中获胜的概率等于:
//p在当前轮中其所有可能对手在上一轮中获胜的概率 × 本轮中p打败这些对手的概率 的和
//再乘以p在上一轮中出线的概率
//即dp[p][r] = dp[p][r - 1] × ∑( dp[op][r - 1] × wp[p][op] )
tmp = 0.0;
//1 << ( r - 1 )表示当前队伍潜在的对手的个数
//当f在1 << ( r - 1 )和1 << r之间漂移时可以选择当前轮的对手
//筛选公式就是op = p ^ f
for ( f = ( 1 << ( r - 1 ) ); ( op = p ^ f ), f < ( 1 << r ); f++ )
tmp += dp[op][r - 1] * wp[p][op];
dp[p][r] = dp[p][r - 1] * tmp;
}
for ( ans = 0, p = 1; p < tm; p++ )//最终答案就是在最后一轮中的最大值
if ( dp[p][rd] > dp[ans][rd] )
ans = p;
printf("%d\n", ans + 1);//注意下标+1,是从0计的,而题目要求是从1计
}
return 0;
}
无注释代码:
#include <stdio.h>
#define MAXTEAMN 128
#define MAXROUNDN 8
double wp[MAXTEAMN][MAXTEAMN];
double dp[MAXTEAMN][MAXROUNDN];
int
main() {
int rd;
int tm;
int p;
int op;
int r;
double tmp;
int ans;
int i, j;
int f;
while ( scanf("%d", &rd), rd != -1 ) {
tm = 1 << rd;
for ( i = 0; i < tm; i++ ) {
for ( j = 0; j < tm; j++ )
scanf("%lf", &wp[i][j]);
dp[i][0] = 1.0;
}
for ( r = 1; r <= rd; r++ )
for ( p = 0; p < tm; p++ ) {
tmp = 0.0;
for ( f = ( 1 << ( r - 1 ) ); ( op = p ^ f ), f < ( 1 << r ); f++ )
tmp += dp[op][r - 1] * wp[p][op];
dp[p][r] = dp[p][r - 1] * tmp;
}
for ( ans = 0, p = 1; p < tm; p++ )
if ( dp[p][rd] > dp[ans][rd] )
ans = p;
printf("%d\n", ans + 1);
}
return 0;
}
单词解释:
single-elimination:n, 单淘汰制
tournament:n, 锦标赛,联赛
eliminate:vt, 消除,排除,淘汰
undefeated:adj, 未被击败的