必威体育Betway必威体育官网
当前位置:首页 > IT技术

循环赛日程安排(C语言)

时间:2019-05-30 10:41:03来源:IT技术作者:seo实验室小编阅读:86次「手机版」
 

循环赛日程表

问题:

(先声明一点,下面我写了两种代码,但是都只能满足 队伍数 = 2的幂次方 的情况)

一年一度的欧洲冠军杯马上就要打响,在初赛阶段采用循环制,设共有n队参加,初赛共进行(n-1)天,每队要和其他各队进行一场比赛。要求每队每天只能进行一场比赛,并且不能轮空。请按照上述需求安排比赛日程,决定每天各队的对手。

对问题的理解

  • 根据排列组合,n 个队伍总共要比赛 n(n-1)/2 场
  • 初赛共进行(n-1)天,那么显而易见每天要比赛 n/2 场
  • 显而易见,会看出一个问题来:这样的话,n 必须为偶数(因为比赛的场数得为整数)

扩充:

  • n为奇数会怎么样?
  • 首先,n队参加,由于每队每天只能进行一场比赛,则至少要比赛(n-1)天,这个很容易理解
  • 已知n为奇数,比赛天数不能是(n-1)天
  • 那么,若比赛天数为 n 天,则每天要比赛 (n-1)/2 场,这样就没问题了

循环赛日程有这么一个规律:

  • 若比赛队数:n恰好为 2的k次方
  • 则可以直接使用分治算法解决这个问题

若 n = 2

  • 第一列的属性是队伍名
  • 第二列属性是 第一天
  • 第一行第二个,表示 1 打 2
  • 第二行第二个,表示 2 打 1
  • 这两个表示的是一个意思,在循环表中

    在这里插入图片描述

    若 n = 4

  • 第一列是属性
  • 第二列到第四列分别代表:第一天到第三天
  • 比如第一行第4个,表示在第三天,1打4

在这里插入图片描述

以此类推…

可以看出,在表格中

  • 左上角 = 右下角
  • 左下角 = 右上角
  • 规律从 n = 2 开始就成立
  • 所以可以用分治算法解决这问题

此代码只适用于 队伍数 = 2的幂次方

#include<iOStream>
#include<stdio.h>
using namespace std;

#define MAXSIZE 64  //暂时允许的最多的参赛队伍数量 
int a[MAXSIZE][MAXSIZE]; //将比赛情况放在这个二维表中 

int GameTable(int n,int k){
	if(n == 2){                     //子问题足够小时
		a[k][0] = k+1;
		a[k][1] = k+2;
		a[k+1][0] = k+2;
		a[k+1][1] = k+1;
	} 
	else{
		GameTable(n/2,k);         //划分子问题
		GameTable(n/2,k+n/2);
		for(int i = k; i < k+n/2; i++){    //填充二维表的右上角
			for(int j = n/2; j < n; j++){
				a[i][j] = a[i+n/2][j-n/2];
			}
		}
		for(int i = k+n/2; i < k+n; i++){   //填充二维表的右下角
			for(int j = n/2; j < n; j++){
				a[i][j] = a[i-n/2][j-n/2];
			}
		}
	}
} 

int main(){
	int n; //队伍数 
	cout<<"please input the number of participating teams(2的幂次方,2到64):";
	cin>>n;
	
	GameTable(n,0);	 
	cout<<"编号 "; 
	for(int i = 1; i <= n; i++)
		cout<<"第"<<i<<"天 "; 
	cout<<endl;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			printf("%4d",a[i][j]);
		}
		cout<<endl;
	}
} 

若一时间不太了解安排循环赛日程中的规律:

管他呀的,直接暴力破解,三重for循环搞起

  • 下面的代码我想了很久,还是只能做到对 n = 2的幂次方 的情况
  • 当n为其他情况时,按下面代码分配一定会造成遗漏,循环表分配是不正确的
#include<iostream>
#include<string.h>
using namespace std;

#define MAXSIZE 64  //暂时限定队伍最大的数量 

int main(){
while(1){
	int team[MAXSIZE+1][MAXSIZE+1], //team不使用下标为零的空间
	//team存放已比赛过的队伍 
		op[MAXSIZE/2][2],//用来输出当天的比赛情况 
		s[MAXSIZE];   //用来检验当日已比赛的队伍 
	int num; //参赛队伍的数量
	int t;
	do{
		cout<<"请输入参赛队伍的数量:";	
		cin>>num;
	}while(num < 2);
	memset(team,0,sizeof(team));

	for(int i = 1; i < num; i++){ 
		memset(s,0,sizeof(s));							 	
		memset(op,0,sizeof(op));
		t = 0;
		for(int j = 1; j <= num; j++){   //表示第i天的第j支队伍的比赛情况 
			if(s[j] == 0){
				for(int k = j+1; k <= num; k++){ //k表示和j配对的对手 
					if(team[j][k] == 1 || s[k] == 1)continue;
					op[t][0] = j;
					op[t++][1] = k;
					s[k] = 1;
					team[j][k] = 1; 
					break;
				}
			}
			if(t == num/2)break; //每天比赛场数满了,进入下一天 
		} 
		
		cout<<"第"<<i<<"天:";
		for(int p = 0; p < t; p++)cout<<"("<<op[p][0]<<","<<op[p][1]<<")  ";
		cout<<endl;
	}
}	
} 

参考资料:

《算法学习与应用 从入门到精通》张玲玲

分治法——循环赛日程安排问题

算法训练 比赛安排

分治法:循环赛日程安排问题

相关阅读

单循环赛制

#!/usr/bin/python3# 文件名: 单循环赛制# 作者:巧若拙# 时间:2019-01-23'''单循环赛制是一种较为公平合理的比赛制度,比赛过程中所

分治法之循环赛日程表的理解和解题思路

一、问题:设有n=2^k个运动员,要进行网球循环赛。现在要设计一个满足以下要求的比赛日程表(1)每个选手必须与其他n-1个选手各赛一场(2)每

单循环赛贝格尔编排法实现

单循环赛,是指所有参赛队伍都需跟其他队伍比赛一次,根据比赛得分,胜负场次来排列名次。比赛队伍为单数时,轮数等于队伍数,为双数时,轮数

分享到:

栏目导航

推荐阅读

热门阅读