题目
设有2n(n<=6)个球队进行单循环比赛,计划在2 n – 1天内完成,每个队每天进行一场比赛。设计一个比赛的安排,使在2n – 1天内每个队都与不同的对手比赛。
例如n=2时的比赛安排:
队 1 2 3 4
比赛 12 34 一天
13 24 二天
14 23 三天
输入格式
每个测试文件只包含一组测试数据,每组输入数据为一个正整数n(n<=6)。
输出格式
对于每组输入数据,输出比赛安排,从第一天的安排开始,每天占一行,每行开头先输出天号,再输出当天的安排,优先给队伍编号小的队伍安排比赛,具体格式见样例输出。
样例
输入
2
输出
<1>1-2,3-4
<2>1-3,2-4
<3>1-4,2-3
解题思路
用f数值标记每个队伍的比赛情况,vis数组标记一天的比赛情况,
三层循环去依次比较比赛的情况 ,
第一层 枚举天数 第二层枚举比赛队伍 第三层枚举上一层的对手。
可以先试试在纸上来写,拿n=3为例,即有8只队伍比赛7天
先看第一天1可以和2,3可以和4,5可以和6,7可以和8
第二天1已经和2比赛过了,所以安排1和3,再接着看2,往后遍历,因为3已经安排和1比赛了,所以2只能和4,5的情况和仿照1的情况所以5-7,6-8。
因此穷举的过程可以得到了,第一重循环跑2^n-1天,第二重循环从小到大跑队伍,第三重循环跑当前队伍的对手,全局上需要开一个二维数组记录哪两个队伍已经比赛过了,在每一天里面,需要开一个一维数组记录在这一天,该队伍是不是已经被安排了。
代码
#include<iostream>
#include<cmath>
using namespace std;
bool f[70][70]={0};//记录j,k队伍比赛的情况
int main()
{
int n;
cin>> n;
for(int i=1;i<=pow(2,n)-1;i++)//天数
{
bool vis[70]={0};//下一天就重置一天队伍的比赛状态(标记是否比赛了)
cout<< "<"<< i<<">" ;
int tep=0;//控制逗号的输出
for(int j=1;j<=pow(2,n);j++)//队伍
{
if(vis[j]==1) continue;//第j个队伍比过赛就跳过
vis[j]=1;//没有就标记为安排过了
for(int k=j+1;k<=pow(2,n);k++)//安排j队伍的对手
{
if(vis[k]==0&&f[j][k]==0) //k在当天没有安排 且j,k没有是过对手
{
vis[k]=1;
f[j][k]=1;
if(tep++) cout<< ",";//第一次是0所以不会输出,在判断了有队伍比赛的时候 下一次就会输出逗号
cout<< j<<"-"<<k;
break ;//安排完 就退出寻找下一个
}
}
}
cout<< endl ;
}
}