循环日程表问题(分治递归)
循环日程表问题
循环日程表问题。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,然后将日程表划分为n=2k−1∗n=2k−1这样的四个子表格,再按照如下方法填充。
- 递归填充方式
- 因为(0,0) 初始化为1了,且每次填充都将其他子表格的左上子表格左上角预先填充了,所以左上子表格的左上角不需要填充。
- 填充右下子表格的左上角为左上子表格的左上角值。
- 填充右上子表格的左上角为左上子表格的左上角值加上子表格当前大小(边长)。
- 同上条一样,填充左下子表格的左上角。
- 填充完毕之后,再递归填充4个子表格,递归出口为n=1。
-
n=8填充一次后的日程表 - 分析:他是由四块拼起来的,左上角是n = 4时的一组解,左下角是左上角每个数加4得到,右上角和右下角分别由左下角和左上角复制得到的。
-
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 const int Max = 100; 7 int g[Max][Max]; 8 void circulateSchedule(int row, int col, int n) 9 { 10 if (n == 1) // 当n== 1时,递归结束 11 return; 12 int half = n / 2; 13 g[row + half][col + half] = g[row][col]; // 右下角 = 左上角 14 g[row + half][col] = g[row][col + half] = g[row][col] + half; //右上角和左下角 都是由左上角加上half 15 circulateSchedule(row, col, half); // 递归左上角 16 circulateSchedule(row, col + half, half); // 右上角 17 circulateSchedule(row + half, col, half);//左下角 18 circulateSchedule(row + half, col + half, half);//右下角 19 } 20 int main() 21 { 22 int n; 23 scanf("%d", &n); 24 g[1][1] = 1; // 初始化左上角第一个 25 circulateSchedule(1, 1, n); 26 for (int i = 1; i <= n; i++) 27 { 28 for (int j = 1; j < n; j++) 29 printf("%d ", g[i][j]); 30 printf("%d\n", g[i][n]); 31 } 32 return 0; 33 }