题解
【提高】循环赛日程表
1 条题解
-
0
解题思路
2^k 个运动员打网球循环赛,每人要和其余人各赛一次,n-1 天内完成,每天每人只赛一次。要求输出日程表。
思路:分治。
先把第一行填成 1~n(代表第一天每个人遇到的对手顺序的雏形)。
然后用分治扩展:
- 每次把当前方阵分成 2×2 块
- 把左上角复制到右下角
- 把右上角复制到左下角
这样每一步规模翻倍,最终得到完整日程表。
为什么可以这样复制? 分治的思想:先解决一半选手的日程,再用对称性补全另一半。左上块是前一半选手之间的比赛,复制到右下块;右上块是后一半选手,复制到左下块,形成交叉比赛。
举例:k=3(8 个选手)
- 第一行:1 2 3 4 5 6 7 8
- 分治复制后得到 8×8 的完整日程表
参考代码
#include <iostream> using namespace std; int a[100][100]; int n; void copy(int tox, int toy, int fromx, int fromy, int r) { for (int i = 0; i < r; i++) { for (int j = 0; j < r; j++) { a[tox + i][toy + j] = a[fromx + i][fromy + j]; } } } void table(int k) { n = 1 << k; for (int i = 0; i < n; i++) a[0][i] = i + 1; // 第一行 for (int r = 1; r < n; r <<= 1) { for (int i = 0; i < n; i += 2 * r) { copy(r, r + i, 0, i, r); // 左上到右下 copy(r, i, 0, r + i, r); // 右上到左下 } } } int main() { int k; cin >> k; table(k); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) cout << a[i][j] << " "; cout << endl; } return 0; }复杂度分析
- 时间复杂度:O(N²),填满 n×n 表
- 空间复杂度:O(N²),日程表数组
- 1