[ICPC2018 WF]Wireless is the New Fiber 题解

题意:

给定一张 \(N\) 个点 \(M\) 条边的无向图,构造一棵树使得和原图度数相等的点最多。 \((1\le N\le10^4,1\le M\le10^5)\)

题解:

感觉思路比较玄学。

首先原图是树特判。

考虑度数越小的点越容易被构造出来,所以按度数从小到大排序。

从度数为 \(1\) 的点入手,直接连向另一个点。

因为要尽量满足度数小的,所以连向第一个度数大于 \(1\) 的。

但是容易遇到没有度数为 \(1\) 的,此时可以将度数最大的当做度数为 \(1\) 的,放弃让这个点相同并进行同样的操作。

因为到了这时,已经没有多个度数为 \(1\) 的点同时连向一个点的情况了,因此总体是成一条链的。

所以应该是每个要满足条件的点上都挂着几个点,而为了联通要形成一条链。

这样做是能保证尽量构造最小的点的:这些点内部是联通了的,因此之后只能靠外部没用的点,而最后面的点显然是没法满足要求了,就直接用。

好玄学啊……我当时想这道题只想出了如何构造一棵度数全部相等的树,然后对这题用处不大……

时间复杂度: \(O(N\log N)\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,sum,d[N],id[N];
vector<pair<int,int> > ans;
inline bool cmp(const int&x,const int&y) {return d[x]<d[y];}
signed main(){
	scanf("%d%d",&n,&m);
	if(m==n-1){
		printf("%d\n%d %d\n",0,n,n-1);
		while(m--) {int u,v;scanf("%d%d",&u,&v);printf("%d %d\n",u,v);}
		return 0;
	}
	while(m--) {int u,v;scanf("%d%d",&u,&v);d[u]++;d[v]++;}
	for(int i=0;i<n;i++) id[i]=i;
	sort(id,id+n,cmp);sort(d,d+n);
	for(int l=0,r1=0,r2=n-1;l<r2;l++){
		while(d[r1]<2) r1++;
		if(d[l]==1){
			d[l]--;d[r1]--;
			ans.push_back(make_pair(l,r1));
			if(l+1==r2) sum++;
		}
		else{
			d[l]--;d[r2]--;sum++;
			ans.push_back(make_pair(l,r2));
			if(l+1==r2) sum++;l--;r2--;
		}
	}
	printf("%d\n%d %d\n",sum,n,n-1);
	for(int i=0;i<n-1;i++) printf("%d %d\n",id[ans[i].first],id[ans[i].second]);
	return 0;
}
posted @ 2021-01-01 22:04  shrtcl  阅读(128)  评论(0编辑  收藏  举报