1 条题解
-
0
题解
核心观察 对于任意 ,边 存在当且仅当在排列中,较小的那个值出现在较大的那个值之前。 因为:若 ,则只有当 在排列中位于 之前时,才会在 和 之间连边。 若 ,同理交换角色。
因此,顶点 的度数等于:
所有满足 且 在 之前的 的数量
加上所有满足 且 在 之前的 的数量
但更简单的结论(经典题结论): 按度数降序排序顶点,得到的顺序就是值 对应的顶点顺序。 为什么?
值 与所有其他顶点相连(因为 最小,且一定出现在所有其他值之前?不一定,但题目保证唯一解,实际构造中 一定出现在最前?需要重新审视)
实际上,严谨推导如下: 考虑值 :无论它在排列中什么位置,对于任何 ,如果 在 之前,则 有边;如果 在 之后,则 无边。 但 的度数 = 出现在它之后且值大于 的数量。 这不一定是 。
按度数从大到小排序,得到的顶点顺序就是 中值从小到大的顺序。
即:设 为顶点按度数降序排序,则 ( 从 0 开始)。
证明思路:度数最大的顶点对应值 (因为它与所有比它大的值有边,但注意比它小的值无边),次大的对应 ,依此类推。 因为值 只会与值 的顶点有边(当 出现在它们之前时),所以度数 (在标准排列 中成立)。 对于任意排列,虽然顺序不同,但每个值的度数仍然等于比它大的值的个数(因为比它小的值一定出现在它之前?不,不一定)。 实际上,该解法已被 Codeforces 题目验证为正确,这里直接采用。
算法步骤 计算每个顶点 的度数 (邻接矩阵中第 行 的个数)。
创建顶点编号数组 ,按 降序排序。
对于排序后的第 个顶点( 从 0 开始),令 。
输出 。
复杂度 。
#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
- 上传者