Description
给定一张n个点m条边的无向图,请找到一个点数最多的点集S,满足:
1.对于点集中任何一个点,它至少与d个点集中的点相邻。
2.仅保留点集中的点后,剩下的图连通。
Input
第一行包含三个正整数n,m,d(2<=n<=200000,1<=m<=200000,1<=d<n),分别表示点数,边数以及度数限制。
接下来m行,每行包含两个正整数a,b(1<=a,b<=n,a不等于b),表示a点和b点之间有一条边。
Output
若无解,输出NIE。
否则第一行输出一个正整数k,表示你找到的点数最多的点集S的点数。
第二行输出k个正整数,按升序依次输出点集中的点的编号,若有多组解,输出任意一组。
Sample Input
4 4 2
1 2
2 3
3 4
4 2
1 2
2 3
3 4
4 2
Sample Output
3
2 3 4
2 3 4
题解:
把所有度数小于d的点都删掉,然后在剩下的图中找一个最大联通块即可。
bfs+dfs;
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200010
#define M 200010
using namespace std;
int point[N],next[M<<1],cnt,n,m,x,y,k,d[N],q[N],f[N],a[N],ans,s[N];
struct use{int st,en;}e[M<<1];
void add(int x,int y){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;d[x]++;
}
void dfs(int x){
f[x]=1;
for (int i=point[x];i;i=next[i])
if (!f[e[i].en]){
s[++s[0]]=e[i].en;
dfs(e[i].en);
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
int h(0),t(0);
for (int i=1;i<=n;i++) if (d[i]<k) q[++t]=i,f[i]=1;
while (h<t){
int u=q[++h];
for (int i=point[u];i;i=next[i]){
d[e[i].en]--;
if (d[e[i].en]<k&&!f[e[i].en])
q[++t]=e[i].en,f[e[i].en]=1;
}
}
for (int i=1;i<=n;i++)
if (!f[i]){
s[0]=0;
s[++s[0]]=i;dfs(i);
if (s[0]>ans){
ans=s[0];
for (int j=1;j<=ans;j++)
a[j]=s[j];
}
}
if (ans==0){cout<<"NIE"<<endl;return 0;}
sort(a+1,a+ans+1);cout<<ans<<endl;
for (int i=1;i<=ans-1;i++)
printf("%d ",a[i]);
printf("%d",a[ans]);
}