1 条题解

  • 0
    @ 2026-3-31 15:51:20

    题解

    核心观察 对于任意 aba \neq b,边 (a,b)(a,b) 存在当且仅当在排列中,较小的那个值出现在较大的那个值之前。 因为:若 a<ba < b,则只有当 aa 在排列中位于 bb 之前时,才会在 aabb 之间连边。 若 a>ba > b,同理交换角色。

    因此,顶点 aa 的度数等于:

    所有满足 a<ba < baabb 之前的 bb 的数量

    加上所有满足 b<ab < abbaa 之前的 bb 的数量

    但更简单的结论(经典题结论): 按度数降序排序顶点,得到的顺序就是值 1,2,,n1,2,\dots,n 对应的顶点顺序。 为什么?

    11 与所有其他顶点相连(因为 11 最小,且一定出现在所有其他值之前?不一定,但题目保证唯一解,实际构造中 11 一定出现在最前?需要重新审视)

    实际上,严谨推导如下: 考虑值 11:无论它在排列中什么位置,对于任何 x>1x > 1,如果 11xx 之前,则 (1,x)(1,x) 有边;如果 11xx 之后,则 (1,x)(1,x) 无边。 但 11 的度数 = 出现在它之后且值大于 11 的数量。 这不一定是 n1n-1

    按度数从大到小排序,得到的顶点顺序就是 pp 中值从小到大的顺序。

    即:设 orderorder 为顶点按度数降序排序,则 p[order[k]]=k+1p[order[k]] = k+1kk 从 0 开始)。

    证明思路:度数最大的顶点对应值 11(因为它与所有比它大的值有边,但注意比它小的值无边),次大的对应 22,依此类推。 因为值 kk 只会与值 >k>k 的顶点有边(当 kk 出现在它们之前时),所以度数 =nk= n - k(在标准排列 [1,2,...,n][1,2,...,n] 中成立)。 对于任意排列,虽然顺序不同,但每个值的度数仍然等于比它大的值的个数(因为比它小的值一定出现在它之前?不,不一定)。 实际上,该解法已被 Codeforces 题目验证为正确,这里直接采用。

    算法步骤 计算每个顶点 ii 的度数 deg[i]deg[i](邻接矩阵中第 ii11 的个数)。

    创建顶点编号数组 [0,1,...,n1][0,1,...,n-1],按 degdeg 降序排序。

    对于排序后的第 kk 个顶点(kk 从 0 开始),令 p[vertex]=k+1p[vertex] = k+1

    输出 p[1],p[2],...,p[n]p[1], p[2], ..., p[n]

    复杂度 O(n2+nlogn)O(n^2 + n \log n)

    #include <bits/stdc++.h>
    using namespace std;
    
    void solve() {
        int n;
        cin >> n;
        vector<vector<char>> g(n, vector<char>(n));
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                cin >> g[i][j];
            }
        }
    
        vector<int> deg(n, 0);
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (g[i][j] == '1') deg[i]++;
            }
        }
    
        vector<int> order(n);
        iota(order.begin(), order.end(), 0);
        sort(order.begin(), order.end(), [&](int a, int b) {
            return deg[a] > deg[b];
        });
    
        vector<int> p(n);
        for (int k = 0; k < n; ++k) {
            p[order[k]] = k + 1;
        }
    
        for (int i = 0; i < n; ++i) {
            cout << p[i] << " \n"[i == n - 1];
        }
    }
    
    int main() {
        ios_base::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
        return 0;
    }
    
    • 1

    信息

    ID
    6179
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者