CodeForces - 1133F2 Spanning Tree with One Fixed Degree(最小生成树)
题目大意
给你一个无向图问是否可以构造一颗生成树,使1号点的度数为d。
解题思路
先把与1号点相连的边的权值都改成INF,其他是0,这样的话如果还用权值为INF的边,说明这些边是必不可少的,如果使用的权值为INF的边大于d,必定无解。否则,将之前必须用到的与1相连边的权值设成-1,其他与1相连的边设成0,其他边设成1,再跑一遍最小生成树就行了,与1相连的边使用到d条之后就不用了。
代码
const int maxn = 2e5+10;
const int maxm = 2e5+10;
int n, m, d, deg[maxn], p[maxn];
int find(int x) {
return p[x]==x ? p[x]:p[x]=find(p[x]);
}
struct I {
int u, v, w;
} e[maxn];
int main() {
cin >> n >> m >> d;
for (int i = 1, a, b; i<=m; ++i) {
cin >> e[i].u >> e[i].v;
if (e[i].u==1 || e[i].v==1) e[i].w = INF;
++deg[e[i].u];
++deg[e[i].v];
}
sort(e+1, e+m+1, [](I a, I b) {return a.w<b.w;});
for (int i = 1; i<=n; ++i) p[i] = i;
int cnt = 0;
for (int i = 1; i<=m; ++i) {
int fa = find(e[i].u);
int fb = find(e[i].v);
if (fa!=fb) {
p[fa] = fb;
if (e[i].w==INF) {
e[i].w = -1;
++cnt;
}
}
}
if (cnt>d || deg[1]<d) {
cout << "NO" << endl;
return 0;
}
for (int i = 1; i<=m; ++i) {
if (e[i].w==INF) e[i].w = 0;
else if (!e[i].w) e[i].w = 1;
}
sort(e+1, e+m+1, [](I a, I b) {return a.w<b.w;});
for (int i = 1; i<=n; ++i) p[i] = i;
vector<P> ans;
for (int i = 1; i<=m; ++i) {
int fa = find(e[i].u);
int fb = find(e[i].v);
if (fa!=fb && ((e[i].w<=0 && d) || e[i].w)) {
p[fa] = fb;
if (e[i].w<=0) --d;
ans.push_back({e[i].u, e[i].v});
}
}
cout << "YES" << endl;
for (auto v : ans) printf("%d %d\n", v.x, v.y);
return 0;
}