4296: [PA2015]Mistrzostwa
Time Limit: 10 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 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
1 2
2 3
3 4
4 2
Sample Output
3
2 3 4
2 3 4
就是把每个度数小于d的点都删去,求最后的联通块的大小。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define N 400005
#define INF 1e9
using 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]);
}
}