AtCoder Beginner Contest 239 F Construct Highway
原题链接 ← Click it
题目大意:简言之就是给你一个森林,问你能不能用\(n - m - 1\)条边生成一个每个点度数为\(d_i\)的树。
解题思路:首先判断每个点的度数之和是否为\(2 * n - 2\),如果不等于,那么直接输出\(-1\)就可以了。其次考虑如何连边,对于每一个连通块而言(用并查集维护连通块),如果这个连通块中所有的点的剩余度数和为0,那么这个连通块就不能和其他的连通块相连了,因此,每一个连通块都至少拿出一个剩余度数来和其他的连通块连通。那么我们可以将剩余度数为1的连通块放一边,剩余度数大于1的连通块放另一边。我们每次都让剩余度数为1的连通块都和剩余度数大于1的连通块连通,如果剩余度数为1的连通块不够用了,那么输出\(-1\),因为假设剩余连通块的个数为\(k\),那么所有剩余连通块的度数和一定大于\(2 * k - 2\)。那么最后的情况是剩下剩余度数为1的两个连通块,那么将这两个连通块连通就得到了这颗生成树了。
参考代码:
typedef long long ll;
typedef pair<int, int> PII;
struct DSU {
int N;
vector<int> pr, size;
DSU (int n) : N(n) {
pr.resize(n + 1);
size.resize(n + 1);
for(int i = 1; i <= N; i ++) {
pr[i] = i;
size[i] = 1;
}
}
int root(int x) {
return pr[x] == x ? x : pr[x] = root(pr[x]);
}
bool same(int x, int y) {
return root(x) == root(y);
}
bool unite(int x, int y) {
int A = root(x), B = root(y);
if(A == B) return 1;
if(size[A] < size[B]) {
pr[A] = B;
size[B] += size[A];
} else {
pr[B] = A;
size[A] += size[B];
}
return 0;
}
};
void solve() {
int n, m;
cin >> n >> m;
DSU dsu(n);
vector<int> d(n + 1);
for(int i = 1; i <= n; i ++) {
cin >> d[i];
}
while(m -- ) {
int a, b;
cin >> a >> b;
d[a] --, d[b] --;
if(d[a] < 0 || d[b] < 0 || dsu.unite(a, b)) {
cout << - 1 << '\n';
return ;
}
}
vector<vector<int>> temp(n + 1);
for(int i = 1; i <= n; i ++) {
for(int _ = 0; _ < d[i]; _ ++) {
temp[dsu.root(i)].push_back(i);
}
}
vector<PII> res;
vector<int> c1;
vector<vector<int>> c2;
for(int i = 1; i <= n; i ++) {
if(temp[i].size() == 1) {
c1.push_back(temp[i].back());
} else if(temp[i].size() > 1){
c2.push_back(temp[i]);
}
}
for(auto it : c2) {
for(int i = 0; i < it.size() - 1; i ++) {
if(c1.empty()) {
cout << -1 << '\n';
return;
}
dsu.unite(c1.back(), it[i]);
res.push_back({c1.back(), it[i]});
c1.pop_back();
}
c1.push_back(it.back());
}
if(c1.size() == 2) {
if(dsu.unite(c1[0], c1[1])) {
cout << - 1 << '\n';
return ;
}
res.push_back({c1[0], c1[1]});
} else {
cout << - 1 << '\n';
return ;
}
if(dsu.size[dsu.root(1)] != n) {
cout << - 1 << '\n';
return ;
}
for(auto it : res) {
cout << it.first << ' ' << it.second << '\n';
}
}

浙公网安备 33010602011771号