对于度数小于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 */