top1编程
← 返回题目
题解

【提高】循环赛日程表

1 条题解

  • 0
    @ 2026-7-31 19:29:45

    解题思路

    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