POJ 3071 Football

题目大意:

        在一次单淘汰制的足球锦标赛中共有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, 未被击败的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值