设有n=2^k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)循环赛一共进行n-1天。
按要求可将比赛日程表设计成有n行和n-1列的一个表。在表中第i行和第j列处填第i个选手在第j天所遇到的选手。用分治法编写为该循环赛设计一张比赛日程表的算法。
题目的分析
采用的是递归的方法,每一次考虑的是n*n的二维数组的内容如何实现比赛。
入口参数采用的是序号和人数,当人数只有2人时直接安排比赛,将2人看作2*2的数组,先看左半部分,依次给左半部分的上下赋值,赋值的依据是根据序号;
然后当人数大于2时继续递归调用函数本身,直到人数为2时执行相关代码后到尾部执行左上角赋值给右下角,左下角赋值给右上角;然后跳出这一层的递归,回到上一层的递归中执行相关代码即可。
注:每次都是先完成2*2的数组数据的填写,再到2^k *2^k扩展。
核心思想:
分治法,将大问题逐渐划分成小问题,然后再合并。
递归处理问题。
巧借下标完成数据最初的赋值。
#include<iostream>
using namespace std;int a[100][100];
int n; //选手的个数
bool check(int num){
if (num == 1)
return true;
else
{
do
{
if (num % 2 == 0)
num = num / 2;
else
return false;
}
while (num != 1);
return true;
}
}
void roundrob(int k,int m)
{
int i,j;
if(m==2)
{
a[k-1][0]=k; //左上角
//a[k-1][1]=k+1;
a[k][0]=k+1; //左下角
// a[k][1]=k;
}
else
{
roundrob(k,m/2); //前半部分
roundrob(k+m/2,m/2); //后
}
for(j=k-1;j<k-1+m/2;j++) //数据复制
{
for(i=0;i<m/2;i++)
{
a[j+m/2][i+m/2]=a[j][i];//左上--》右下
a[j][i+m/2]=a[j+m/2][i]; //左下--》右上
}
}
}
int main()
{
int n;
//验证输入的数据是否为2^k
while(1)
{
system("cls");
cout<<"请输入运动员的人数,为2^k个:";
cin>>n;
if(check(n))
{
roundrob(1,n);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
cout<< a[i][j] << " ";
}
cout<<endl;
}
}
else
{
cout<<"输入错误,请重新输入!"<<endl;
}
system("pause");
}
return 0;
}