[SDOI2019]热闹又尴尬的聚会(图论+set+构造)
据说原数据可以让复杂度不满的暴力O(Tn^2)过掉……O(Tn^2)方法类似于codeforces一场div2的E题
有一种比较好的方法:每次找出原图G中度最小的点加入q,然后将相邻的点加入新图G'。这显然能够得到一个最大的独立集。而p可以在维护度最小的点最大这一过程中,把G的所有点加入集合p。因为set带一个log,所以复杂度为O(Tmlogn)。
证明:满足(p+1)(q+1)>n即可。删除的q节点中d的度数和满足Σ(d[i]+1)=n,其中i∈q,然后max{d[i]}q>=n,于是(max{d[i]}+1)q>n,而p>=max{d[i]},所以命题成立。
#include<bits/stdc++.h> using namespace std; const int N=1e4+7; int n,m,n1,n2,len,deg[N],vis[N],s1[N],s2[N],b[N]; vector<int>G[N]; struct node{int u,d;}a[N]; bool operator<(node a,node b){return a.d==b.d?a.u<b.u:a.d<b.d;} typedef set<node>::iterator iter; set<node>S; inline int read() { int x=0,w=0; char ch=0; while(!isdigit(ch))w|=ch=='-',ch=getchar(); while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return w?-x:x; } int main() { int T;scanf("%d",&T); while(T--) { n=read(),m=read(); n1=n2=len=0; for(int i=1;i<=n;i++)G[i].clear(),deg[i]=vis[i]=0,a[i]=(node){i,0}; for(int i=1;i<=m;i++) { int x=read(),y=read(); G[x].push_back(y),G[y].push_back(x); deg[x]++,deg[y]++,a[x].d++,a[y].d++; } for(int i=1;i<=n;i++)S.insert(a[i]); int mxd=-1,mx=0; while(!S.empty()) { int u=(*S.begin()).u; if(deg[u]>mxd)mxd=deg[u],mx=len; S.erase(S.begin()); b[++len]=u,s2[++n2]=u,vis[u]=1; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; iter it=S.find((node){v,deg[v]}); if(it==S.end())continue; S.erase(it),b[++len]=v; for(int j=0;j<G[v].size();j++) { int t=G[v][j]; it=S.find((node){t,deg[t]}); if(it==S.end())continue; S.erase(it),S.insert((node){t,--deg[t]}); } } } for(int i=mx+1;i<=len;i++)s1[++n1]=b[i]; printf("%d",n1);for(int i=1;i<=n1;i++)printf(" %d",s1[i]); printf("\n%d",n2);for(int i=1;i<=n2;i++)printf(" %d",s2[i]); puts(""); } }