【bzoj4296: [PA2015]Mistrzostwa】图论


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 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]);
	}
}


猜你喜欢

转载自blog.csdn.net/bingoo0o0o/article/details/78725681