【bzoj4296: [PA2015]Mistrzostwa】图论

来源:互联网 发布:网络克隆交换机 编辑:程序博客网 时间:2024/05/21 03:56


4296: [PA2015]Mistrzostwa

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 231  Solved: 99
[Submit][Status][Discuss]

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

Sample Output

3
2 3 4

就是把每个度数小于d的点都删去,求最后的联通块的大小。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define N 400005#define INF 1e9using namespace std;int b[N],vis[N],num[N],fir[N],k,n,m,d,l,r,ans,mn=INF,pos,Vis[N];struct he{int r,nx;}a[N];void add(int l,int r){k++;a[k].r=r;a[k].nx=fir[l];fir[l]=k;}void dfs(int x){vis[x]=1;for(int i=fir[x];i;i=a[i].nx)if(!vis[a[i].r]){num[a[i].r]--;if(num[a[i].r]<d) dfs(a[i].r);}}void find(int x,int &num1,int u){vis[x]=u;num1++;for(int i=fir[x];i;i=a[i].nx)if(!vis[a[i].r]) find(a[i].r,num1,u);}void work(int x,int u){b[++b[0]]=x;Vis[x]=1;for(int i=fir[x];i;i=a[i].nx)if(vis[a[i].r]==u&&!Vis[a[i].r])work(a[i].r,u);}int read(){int sum=0;char ch=getchar();    while(!(ch>='0'&&ch<='9'))ch=getchar();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();    return sum;}int main(){n=read();m=read();d=read();for(int i=1;i<=m;i++){l=read();r=read();add(l,r);add(r,l);num[l]++;num[r]++;}for(int i=1;i<=n;i++)if(!vis[i]&&num[i]<d){dfs(i);}ans=0;for(int i=1;i<=n;i++)if(!vis[i]){int num1=0;find(i,num1,i+1);if(num1>ans) ans=num1,pos=i;}if(ans==0) printf("NIE\n");else {work(pos,pos+1);sort(b+1,b+1+ans);printf("%d\n",ans);for(int i=1;i<=ans;i++)printf("%d ",b[i]);}}


原创粉丝点击