2019暑假集训8.23(problem2.party)

对于度数小于d的点先删去,删去后另一些点的度数变到小于d了也删去,最后求最大联通块。

删点时可用栈来保存,把度数小于d的都压入栈,保证小于d的点都会被删去。

最后求最大连通块用并查集就可以实现。

注意!最后被邀请去的人是直接或间接联通,所以是联通图,而不存在中间有一个人没被邀请,但是和他有关系的人被邀请了,这种关系只在邀请了的人中体现(我就错在这,把题目想复杂了)。

#include<bits/stdc++.h>
#define N 200002
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct EDGE{
    int nextt,to,me;
}w[N*2];
int tot=0,head[N],vis[N],fa[N],du[N],sum[N],n,d;
queue<int>q;
void add(int a,int b)
{
    tot++;
    w[tot].nextt=head[a];
    w[tot].me=a;
    w[tot].to=b;
    head[a]=tot;
}
void work()//删去度数小于d的点 
{
    for(int i=1;i<=n;++i)
      if(du[i]<d)q.push(i),vis[i]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=w[i].nextt)
        {
            int v=w[i].to;
            du[v]--;
            if(du[v]<d&&!vis[v])q.push(v),vis[v]=1;//记得打上标记说明已经删去 
        }
    }
}
int get(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=get(fa[x]);
}
int main()
{
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout);
    n=read();int m=read();d=read();
    int maxx=0;
    for(int i=1;i<=m;++i)
    {
        int a=read(),b=read();
        du[a]++;du[b]++;
        add(a,b);add(b,a);
    }
    for(int i=1;i<=n;++i)
      fa[i]=i,sum[i]=1;
    work();
    int id;
    for(int i=1;i<=tot;++i)//找出最大的连通块,可用并查集记录 
    {
        if(du[w[i].me]>=d&&du[w[i].to]>=d)
        {
            int f1=get(w[i].me),f2=get(w[i].to);
            if(f1==f2)continue;
            fa[f1]=f2;
            sum[f2]+=sum[f1];
            if(sum[f2]>maxx)maxx=sum[f2],id=f2;
        }
    }
    printf("%d\n",maxx);
    for(int i=1;i<=n;++i)
      if(get(i)==id)printf("%d ",i);
} 
/*
4 4 2
1 2
2 3
3 4
4 2

5 4 3
1 2
1 3
1 4
1 5

11 9 1
1 2
1 3
1 4
1 5
6 7
6 8
6 9
6 10
6 11
*/
View Code

猜你喜欢

转载自www.cnblogs.com/yyys-/p/11402122.html