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
HINT
请不要提交,尚无SPJ
Source
By Claris
首先为了满足第一个限制,原图中度数小于d的点肯定都不能留
然后就剩下一些联通块,其中每个点度数都是大于等于d的
然后dfs看大小,找一个最大的联通块.
这题挺简单的,为什么没多少人做..
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 200010
#define GET (ch>='0'&&ch<='9')
using namespace std;
void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
int n,m,D,ans,cnt;
int u,v,top;
int d[MAXN],del[MAXN],q[MAXN];
int sta[MAXN],block[MAXN];
int head=1,tail;
struct edge { int to;edge *next; }e[MAXN<<1],*prev[MAXN];
void insert(int u,int v) { d[u]++;e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top]; }
void dfs(int x)
{
if (del[x]) return;
sta[++cnt]=x;del[x]=1;
for (edge *i=prev[x];i;i=i->next) if (!del[i->to]) dfs(i->to);
}
int main()
{
for (in(n),in(m),in(D);m;m--) in(u),in(v),insert(u,v),insert(v,u);
for (int i=1;i<=n;i++) if (d[i]<D) q[++tail]=i,del[i]=1;
while (head<=tail)
{
int x=q[head++];
for (edge *i=prev[x];i;i=i->next)
if ((--d[i->to])<D&&!del[i->to]) q[++tail]=i->to,del[i->to]=1;
}
for (int i=1;i<=n;i++)
if (!del[i])
{
cnt=0;dfs(i);
if (cnt>ans) { ans=cnt; for (int j=1;j<=cnt;j++) block[j]=sta[j]; }
}
sort(block+1,block+ans+1);
if (!ans) return puts("NIE"),0;
printf("%d\n",ans);
for (int i=1;i<=ans;i++) printf(i==n?"%d\n":"%d ",block[i]);
}