- 给定一张(n)个点(m)条边的图。
- 要求构造两个子图(可以有重复点),第一个子图中有任意多个点且所有点度数大于等于(p),第二个子图有(q)个点且是一个独立集。
- (p,q)由你自己决定,只需满足(lfloorfrac n{p+1} floorle q)且(lfloorfrac n{q+1} floorle p)。
- 数据组数(le32),(nle10^4,mle10^5)
联合构造题
要单独构造一个最大独立集显然是不太可能的事。
分析(lfloorfrac n{p+1} floorle qLeftrightarrowfrac n{p+1}<q+1Leftrightarrow(p+1)(q+1)>n),而另一个条件也同样可以转化成这个式子。
那么,就容易想到把这两个东西合起来一起构造。
具体地,对于第一个子图,我们可以直接枚举最小的度数(p),那么所有比这个度数小的点都将被删掉。
每删掉一个点,我们都把它尝试加入独立集,由于这个点度数肯定小于最终的(p),即便它被加入了独立集,也只会让小于(p)个数无法再加入独立集。
这么一看,显然可以满足((p+1)(q+1)>n),于是这道题就做完了。
代码:(O(Tm))
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 10000
#define M 100000
#define Pr pair<int,int>
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,m,A[N+5],B[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[2*M+5];
int d[N+5],nB[N+5],vis[N+5];queue<int> q[N+5];
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc(' ');}
I void writeln() {pc('
');}
}using namespace FastIO;
int main()
{
RI Tt,i,x,y,k,p,a,b,ct;read(Tt);W(Tt--)
{
for(read(n,m),ee=0,i=1;i<=n;++i) {lnk[i]=d[i]=nB[i]=0,vis[i]=-1;W(!q[i].empty()) q[i].pop();}//清空
for(i=1;i<=m;++i) read(x,y),add(x,y),add(y,x),++d[x],++d[y];//初始图,统计每个点度数
for(i=1;i<=n;++i) q[d[i]].push(i);for(a=b=p=0;p<=n&&(p+1)*(b+1)<=n;++p) W(!q[p].empty())//枚举最小度数,然后删去最小度数的点
{
if(k=q[p].front(),q[p].pop(),~vis[k]) continue;vis[k]=p,!nB[k]&&(B[++b]=k);//已访问过的删去,然后尝试加入独立集
for(i=lnk[k];i;i=e[i].nxt) !~vis[e[i].to]&&
(!nB[k]&&(nB[e[i].to]=k),d[e[i].to]>p&&(q[--d[e[i].to]].push(e[i].to),0));//更新相连点度数,如果k在独立集中还要让相连点无法进入
}
for(i=1;i<=n;++i) !~vis[i]&&(A[++a]=i);//没被访问到的点度数≥最小度数,作为第一子图中的点
for(write(a),i=1;i<=a;++i) write(A[i]);writeln();for(write(b),i=1;i<=b;++i) write(B[i]);writeln();//输出构造方案
}return clear(),0;
}