网球循环赛日程表
问题描述:
设有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 );
}
运行结果: