循环日程表问题
循环日程表问题。 n=2k 个运动员进行网球循环赛,需要设计比赛日程表。每个选手必须与其他 n−1 个选手各赛一次;每个选手一天只能赛一次;循环赛一共进行 n−1 天。按此要求设计一张比赛日程表,该表有 n 行和
n−1 列,第 i 行j 列为第 i 个选手第j 天遇到的选手。
该问题和棋盘问题很像,都可以通过递归思想来解。
-
递归三部曲
- 划分问题:将 n=2k 个运动员划分为两组 n=2k−1 个运动员。
- 递归求解:递归填充 n=2k−1 个运动员的日程表,填充方式见下面,递归出口为 n=1 。
- 合并问题:该问题不需要合并。
将日程表看做是一个
n=2k∗n=2k
的一个表格,先初始化
(0,0)
位置为
1
,然后将日程表划分为
-
递归填充方式
- 因为 (0,0) 初始化为 1 了,且每次填充都将其他子表格的左上子表格左上角预先填充了,所以左上子表格的左上角不需要填充。
- 填充右下子表格的左上角为左上子表格的左上角值。
- 填充右上子表格的左上角为左上子表格的左上角值加上子表格当前大小(边长)。
- 同上条一样,填充左下子表格的左上角。
- 填充完毕之后,再递归填充
4 个子表格,递归出口为 n=1 。
循环日历表问题算法实现
void circulateSchedule(int row, int column, int n) {
// 递归出口
if(n == 1) {
return ;
}
// 将2^k*2^k的表格分成2^(k-1)*2^(k-1)的四个子表格
int half = n / 2;
// 每个表格的左上角赋值
// 左上子表格等于右下子表格,右上子表格等于左下子表格
// 右上子表格等于左上子表格加上子表格大小
table[row + half][column + half] = table[row][column];
table[row][column + half] = table[row + half][column] = table[row][column] + half;
// 递归四个子表格
circulateSchedule(row, column, half);
circulateSchedule(row, column + half, half);
circulateSchedule(row + half, column, half);
circulateSchedule(row + half, column + half, half);
}
测试主程序
#include <iostream>
using namespace std;
const int maxNum = 1 << 10;
int table[maxNum][maxNum];
void circulateSchedule(int row, int column, int n) {
// 递归出口
if(n == 1) {
return ;
}
// 将2^k*2^k的表格分成2^(k-1)*2^(k-1)的四个子表格
int half = n / 2;
// 每个表格的左上角赋值
// 左上子表格等于右下子表格,右上子表格等于左下子表格
// 右上子表格等于左上子表格加上子表格大小
table[row + half][column + half] = table[row][column];
table[row][column + half] = table[row + half][column] = table[row][column] + half;
// 递归四个子表格
circulateSchedule(row, column, half);
circulateSchedule(row, column + half, half);
circulateSchedule(row + half, column, half);
circulateSchedule(row + half, column + half, half);
}
int main() {
// 选手个数,n=2^k
int n;
while(true) {
cout << "请输入选手个数,0则退出程序:";
cin >> n;
if(!n) {
break;
}
// 初始化(0,0)点
table[0][0] = 1;
// 生成循环日程表
circulateSchedule(0, 0, n);
// 输出表
for(int i = 0; i < n; i++) {
for(int j = 1; j < n; j++) {
cout << table[i][j] << "\t";
}
cout << endl << endl << endl;
}
}
return 0;
}
输出数据
请输入选手个数,0则退出程序:2
2
1
请输入选手个数,0则退出程序:4
2 3 4
1 4 3
4 1 2
3 2 1
请输入选手个数,0则退出程序:8
2 3 4 5 6 7 8
1 4 3 6 5 8 7
4 1 2 7 8 5 6
3 2 1 8 7 6 5
6 7 8 1 2 3 4
5 8 7 2 1 4 3
8 5 6 3 4 1 2
7 6 5 4 3 2 1
请输入选手个数,0则退出程序:0
Process returned 0 (0x0) execution time : 27.790 s
Press any key to continue.