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;
} 
posted @ 2021-02-23 23:22  shuitiangong  阅读(86)  评论(0编辑  收藏  举报