【PA2015】【BZOJ4296】Mistrzostwa

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

你可能感兴趣的:(连通块)