【问题描述】设有n=24个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能参赛一次;
(3)循环赛在n-1天内结束。
请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行,第j列处填入第i个选手在第j天所遇到的选手。其中1≤i≤n,1≤j≤n-1。编写程序,输出k=4时的比赛日常表(矩阵)。
[实验提示]
我们可以按分治策略将所有的选手分为两半,则n个选手的比赛日程表可以通过n/2个选手的比赛日程表来决定。递归地用这种一分为二的策略对选手进行划分,直到只剩下两个选手时,比赛日程表的制定就变得很简单。这时只要让这两个选手进行比赛就可以了。
1 | 2 | 3 | 4 | 5 | 6 | 7 | |||||||||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ||||||||||||
2 | 1 | 4 | 3 | 6 | 5 | 8 | 7 | ||||||||||||
3 | 4 | 1 | 2 | 7 | 8 | 5 | 6 | ||||||||||||
1 | 2 | 3 | 4 | 3 | 2 | 1 | 8 | 7 | 6 | 5 | |||||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 1 | 2 | 3 | 4 | ||||||||
1 | 2 | 1 | 4 | 3 | 6 | 5 | 8 | 7 | 2 | 1 | 4 | 3 | |||||||
1 | 2 | 3 | 4 | 1 | 2 | 7 | 8 | 5 | 6 | 3 | 4 | 1 | 2 | ||||||
2 | 1 | 4 | 3 | 2 | 1 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
(1) (2) (3)
图1 2个、4个和8个选手的比赛日程表
[实验步骤]
采用递归方式设计并实现算法并准备测试用例,修改并调试程序,直至正确为止;
应用设计的算法和程序求锦标赛问题;
去掉测试程序,将你的程序整理成功能模块存盘备用.
算法分析:
根据相应的分析,我们需要为最开始的n=2的情况进行人工的赋值。之后我们要做的就是扩大这个矩阵的维度,此时n变成4,那么接下来我们就需要依据这个左上角的矩阵的数据,去依次完善左下角,右上角和右下角的矩阵的内容。经过分析发现相应的矩阵中的数值是有规律的,所以可以依次循环赋值即可。
此时我们根据k的值进行下一次大的循环,此时继续为n进行乘以2处理,然后重复如上的内容即可将该矩阵赋值完成。
代码实现部分:
#include<iostream>
using namespace std;
#define MAX 101
int k;
int a[MAX][MAX];
void plan(int k){
int i,j,n,t,temp;
n=2; //k=1的时候 即2的一次方的结果
a[1][1]=1;a[1][2]=2;a[2][1]=2;a[2][2]=1;
for(t=1;t<k;t++){
temp=n;
n=n*2;
for(i=temp+1;i<=n;i++)
for(j=1;j<=temp;j++)
a[i][j]=a[i-temp][j]+temp;
for(i=1;i<=temp;i++)
for(j=temp+1;j<=n;j++)
a[i][j]=a[i+temp][(j+temp)%n];
for(i=temp+1;i<=n;i++)
for(j=temp+1;j<=n;j++)
a[i][j]=a[i-temp][j-temp];
}
}
int main(){
cout<<"please input the k:";
cin>>k;
plan(k);
int i,j,res=1;
for(i=1;i<=k;i++)
res*=2;
for(i=1;i<=res;i++)
for(j=1;j<=res;j++){
cout<<a[i][j]<<" ";
if(j==res)
cout<<endl;
}
return 0;
}
实验结果: