1. 程式人生 > 實用技巧 >題解 CF404C 【Restore Graph】

題解 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;
}