题解 CF404C 【Restore Graph】
思路
这道题从最短路的角度去考虑可能不是很好想,可以考虑从构造的角度,只要确定了起点,那么图的框架就可以顺利成章的构造出来。
最短路可以不考虑,考虑最短路只会使答案复杂化,建出一颗树,路径唯一,就不需要考虑最短路了;其次,有每个点的度数不可以大于k,所以没必要连的边就尽量不连。
考虑度数,除了距离为 0 的节点的边都是连的儿子节点,其他节点在添加父节点时一定有一条边连向了父节点,即只能添加 \(k-1\) 个儿子,而距离为 0 的点就可以连\(k\)个儿子。
首先通过判断距离为x和距离为\(x+1\)的点的个数关系,即(距离为\(x\)的点的个数 \(\times (k - 1)\) > 距离为\(x+1\)的点的个数),距离为 0 的点特殊处理一下,同时判断一下,有可能不存在距离为 0 的点或者存在多个距离为 0 的点都是不合法的,建边就从距离为 \(x\) 的点连向距离为 \(x+1\) 的点就可以。
代码实现 (操作有点累赘)
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e6 + 50;
inline int read () {
int x = 0, f = 1; char ch = getchar();
for (;!isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
return x * f;
}
int n, k;
struct Node {
int d, id;
} node[maxn];
int cnt[maxn];
vector <int> vec[maxn];
struct Ans {
int from, to;
} ans[maxn];
bool cmp (Node A, Node B) { return A.d < B.d;}
int Max;
signed main () {
n = read(), k = read();
for (int i = 1; i <= n; i++) {
node[i].d = read();
node[i].id = i;
Max = max (node[i].d, Max);
}
int cnt = 0;
sort (node + 1, node + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
if (node[i].d == 0) {
if (cnt != 0) {
return puts("-1"), 0;
}
cnt++;
}
vec[node[i].d].push_back(node[i].id);
}
for (int i = 1; i < Max; i++) {
if ((long long)vec[i].size() * (k - 1) < vec[i + 1].size()) return puts("-1"), 0;//记得开long long,不然会爆
}
if (cnt == 0) return puts("-1"), 0;
if (k < vec[1].size()) return puts("-1"), 0;
int oper = 0, js = 0;
for (int i = 1; i <= n; i++) {
if (node[i].d == 0) {
continue;
}
if (node[i].d - node[i - 1].d == 0) {
if (js == k) {
js = 1, ++oper;
ans[i].from = vec[node[i].d - 1][oper], ans[i].to = node[i].id;
} else if (js == k - 1 && node[i].d != 1) {
js = 1, ++oper;
ans[i].from = vec[node[i].d - 1][oper], ans[i].to = node[i].id;
} else if (js == k - 1 && node[i].d == 1) {
js ++;
ans[i].from = vec[node[i].d - 1][oper], ans[i].to = node[i].id;
}else {
js++;
ans[i].from = vec[node[i].d - 1][oper], ans[i].to = node[i].id;
}
} else if (node[i].d - node[i - 1].d == 1) {
oper = 0, js = 1;
ans[i].from = vec[node[i].d - 1][oper], ans[i].to = node[i].id;
}
}
printf ("%d\n", n - 1);
for (int i = 2; i <= n; i++) {
printf ("%d %d\n", ans[i].from, ans[i].to);
}
return 0;
}