问题描述
设有n=2^k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能参赛一次;
(3)循环赛在n-1天内结束。
请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行,第j列处填入第i个选手在第j天所遇到的选手。其中1≤i≤n,1≤j≤n-1。
思路
分治,可以用递归或者迭代实现
迭代:
#include<iostream>
#include<cmath>
using namespace std;
int a[100][100];
void gametable(int k)
{
int n,tmp,i,j,t;
n=2;//最小的表,相当于递归出口
a[1][1]=1;a[1][2]=2;
a[2][1]=2;a[2][2]=1;
for(t=1;t<k;t++)//迭代填表,依次处理2^2...2^k个选手的比赛日程
{
tmp=n;
n*=2;
for(i=tmp+1;i<=n;i++)
for(j=1;j<=tmp;j++)
a[i][j]=a[i-tmp][j]+tmp;//左下角与左上角相对应
for(i=1;i<=tmp;i++)//左下角抄到右上角
for(j=tmp+1;j<=n;j++)
a[i][j]=a[i+tmp][(j+tmp)%n];
for(i=tmp+1;i<=n;i++)//左上角抄到右下角
for(j=tmp+1;j<=n;j++)
a[i][j]=a[i-tmp][j-tmp];
}
cout<<"参赛人数为:"<<n<<endl;
cout<<"(第i行第j列表示和第i个选手在第j天比赛的选手序号)"<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cout<<a[i][j]<<' ';
cout<<endl;
}
}
int main()
{
int k;
cout<<"比赛选手个数为n(n=2^k),请输入参数K(K>0):"<<endl;
while(cin>>k&&k)
{
gametable(k);
cout<<endl;
}
return 0;
}
递归:
#include<iostream>
using namespace std;
int n,a[100][100],len;
void UpRightCopy(int n)
{
for(int i=1;i<=n;i++)
for(int j=n+1;j<=2*n;j++)
a[i][j]=a[i][j-n]+n;
}
void DownRightCopy(int n)
{
for(int i=n+1;i<=2*n;i++)
for(int j=n+1;j<=2*n;j++)
a[i][j]=a[i-n][j-n];
}
void LeftDownCopy(int n)
{
for(int i=n+1;i<=2*n;i++)
for(int j=1;j<=n;j++)
a[i][j]=a[i-n][j]+n;
}
void turn(int n)
{
if(n==1)
a[1][1]=1;
else
{
turn(n/2);
DownRightCopy(n/2);
UpRightCopy(n/2);
LeftDownCopy(n/2);
}
}
int main()
{
while(cin>>n)
{
len=1;
for(int i=1;i<=n;i++)
len*=2;
n=len;
turn(n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<a[i][j]<<' ';
cout<<endl;
}
}
return 0;
}