[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;
}