c语言-网球循环赛日程表

网球循环赛日程表

问题描述:
设有n个运动员要进行网球循环赛。设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次。
(2)每个选手一天只能赛一次
(3)当n是偶数时循环赛进行n-1天,当n是奇数时循环赛进行n天。*

设计思路:
①边界情况n=2
②划分成2个偶数,递归+连线
③划分成1个奇数和1个偶数,补充成2个偶数或者2个奇数的情况,处理完后移除补充的人员
④划分成2个奇数,递归+轮空的两个进行比赛+连线
连线即:假设有6个人比赛,那么他们的比赛情况如图:
在这里插入图片描述

#include<stdio.h>
#include<string.h>

#define MAXN 20
#define MAXD 20

// schedule[d][p] 即选手p在第d天比赛的选手.
// schedule[d][p] == 0 即p轮空 
int schedule[MAXD][MAXN];

//初始化赛程表
void initSchedule ()
{
	memset ( schedule , 0 , sizeof ( schedule ) );
}

//两个人比赛的情况
void setMatch ( int day , int player1 , int player2 )
{
	schedule[day][player1] = player2;
	schedule[day][player2] = player1;
}

//找到轮空的选手
int findIdlePlayer ( int day , int firstPlayer , int playerNum )
{
	for (int i = firstPlayer; i < firstPlayer+playerNum; i++)
	{
		if (schedule[day][i]==0)
		{
			return i;
		}
	}
}

//考虑两个组之间的比赛情况,假设两组X,Y分别有playerNum个选手
//比赛从firstDay开始,持续playerNum天
//可以用连线的方式进行比赛,即: 
// day1: x1-y1, x2-y2, x3-y3
// day2: x1-y2, x2-y3, x3-y1
// day3: x1-y3, x2-y1, x3-y2
// ...
//matchingOffset表示因为之前组内比赛的时候轮空互相比赛
//现在只需要比赛:playerNum-machingOffset天 
void arrangeScheduleBetweenGroups ( int firstDay , int firstPlayer1 ,
	int firstPlayer2 , int playerNum , int matchingOffset )
{
	for (int d = 0; d < playerNum-matchingOffset; d++)
	{
		for (int p = 0; p < playerNum; p++)
		{
			int player1 = p + firstPlayer1;
			int player2 = firstPlayer2 + ( d + p + matchingOffset ) % playerNum;
			setMatch ( firstDay+d , player1 , player2 );
		}
	}
}

//安排整体的比赛日程表
void arrangeSchedule ( int firstDay , int firstPlayer , int playerNum )
{
	if (playerNum == 2)
	{
		setMatch ( firstDay , firstPlayer , firstPlayer + 1 );
		return;
	}
	if (playerNum%2==0)
	{
		int halfPlayerNum = playerNum / 2;
		arrangeSchedule ( firstDay , firstPlayer , halfPlayerNum );
		arrangeSchedule ( firstDay , firstPlayer + halfPlayerNum , halfPlayerNum );
		if (halfPlayerNum%2==0)
		{
			arrangeScheduleBetweenGroups ( firstDay+halfPlayerNum-1 , firstPlayer , firstPlayer + halfPlayerNum ,halfPlayerNum, 0 );

		}
		else
		{
			for (int d = firstDay; d < firstDay+halfPlayerNum; d++)
			{
				int player1 = findIdlePlayer ( d , firstPlayer , halfPlayerNum );
				int player2 = findIdlePlayer ( d , firstPlayer + halfPlayerNum , halfPlayerNum );
				setMatch ( d , player1 , player2 );
			}
			arrangeScheduleBetweenGroups ( firstDay+halfPlayerNum , firstPlayer , firstPlayer + halfPlayerNum , halfPlayerNum , 1 );
		}
	}
	else
	{
		int playerNum1 = playerNum + 1;
		int halfPlayerNum = playerNum1 / 2;
		arrangeSchedule ( firstDay , firstPlayer , playerNum1 );
		int fakePlayer = firstPlayer + playerNum;
		for (int d = firstDay; d < firstDay+playerNum; d++)
		{
			int rival = schedule[d][fakePlayer];
			schedule[d][rival] = 0;
			schedule[d][fakePlayer] = 0;
		}
	}
}

//输出日程表
void printSchedule (int n)
{
	int days = 0;
	if (n % 2 == 0)
		days = n - 1;
	else
		days = n;
	printf ( "     " );
	for (int i = 1; i <= days; i++)
	{
		printf ( " [D%02d]" , i );
	}
	printf ( "\n" );
	for (int i = 1; i <= n; i++)
	{
		printf ( " [%02d] " , i );
		for (int j = 1; j <= days; j++)
		{

			if (schedule[j][i] == 0)
				printf ( "  -   " );
			else
				printf ( "  %02d  " , schedule[j][i] );
		}
		printf ( "\n" );
	}
}

int main ()
{
	int n = 0;
	printf ( "请输入参赛人数:" );
	scanf_s ( "%d" , &n );
	initSchedule ();
	arrangeSchedule ( 1 , 1 , n );
	printSchedule ( n );
}

运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值