LOJ3113
SOL
对于题目的 p , q p,q p,q的限制,我们可以转化成 ( p + 1 ) ( q + 1 ) > n (p+1)(q+1)\gt n (p+1)(q+1)>n,q是求最大独立集,但是此题不是二分图,无法用网络流等方式。
我们需要最大化地求 p , q p,q p,q。
- 构造方法
先贪心地求出最大的 p p p。
不妨把“加点”的思路转化为“删点“,即已经有一个合法的图,我们考虑让它更大。删除度数最小的点,才可能增大答案。所以一路删点记录最大值的时刻,即为 p p p的最大值方案。
接下来构造合法的问题2方案。
我们思考如下做法:
现在原图中选出度数最小的点 P P P,删除,存入点集 S S S中,并将与 P P P相连的所有点一并删除,再更新剩下的点的度数。重复这一过程,直到删完所有点。
最后得到的点集 S S S即为方案二答案。
- 证明:
1.S对于问题二合法。
显然。
2.S集合的大小 q q q,满足 ( q + 1 ) ( p + 1 ) > n (q+1)(p+1)\gt n (q+1)(p+1)>n
设 d P i d_{P_i} dPi表示 S S S集合中点 P i P_i Pi度数。
n = ∑ i = 1 ∣ S ∣ ( 即 为 q ) ( d P i + 1 ) n=\sum_{i=1}^{|S|( 即为q)} (d_{P_i}+1) n=∑i=1∣S∣(即为q)(dPi+1)
设
D
m
a
x
Dmax
Dmax为
d
P
i
d_{P_i}
dPi中的最大值,问题一中构造出的最大值为
p
p
p。
由于
p
p
p是最大的答案,故
p
≥
D
m
a
x
p\ge Dmax
p≥Dmax(否则
p
=
D
m
a
x
p=Dmax
p=Dmax)
(
p
+
1
)
∗
(
q
+
1
)
≥
(
D
m
a
x
+
1
)
∗
(
q
+
1
)
>
(
D
m
a
x
+
1
)
∗
q
≥
n
(p+1)*(q+1)\ge(Dmax+1)*(q+1)\gt (Dmax+1)*q\ge n
(p+1)∗(q+1)≥(Dmax+1)∗(q+1)>(Dmax+1)∗q≥n.
证毕。
- 总结
写一个set支持一下排序删点加点。
为了简化代码复杂度,我们可以直接做一遍2过程,取 p = D m a x p=Dmax p=Dmax即可。
CODE
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define ri register int
#define in red()
#define gc getchar()
#define cs const
#define ll long long
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=1e4+10,M=2e5+10;
int head[N],cnt=1,nxt[M],to[M],d[N],n,m,top,stk[N],dmx,pos,ban[N];
inline void adde(int u,int v){
++d[u];++d[v];
nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;
nxt[++cnt]=head[v];head[v]=cnt;to[cnt]=u;
}
typedef pair<int,int> pi;
#define fi first
#define se second
set<pi> s;
#define It set<pi>::iterator
vector<int>del;
inline void delet(int u){
for(ri i=head[u];i;i=nxt[i]){
int v=to[i];
if(ban[v])continue;
s.erase(pi(d[v],v));
s.insert(pi(--d[v],v));
}
}
inline void solve(){
n=in;m=in;
memset(head,0,(n+1)*sizeof(int));
memset(d,0,(n+1)*sizeof(int));
memset(ban,0,(n+1)*sizeof(int));
cnt=1;top=0;dmx=0;
del.clear();
for(ri i=1;i<=m;++i)adde(in,in);
for(ri i=1;i<=n;++i)s.insert(pi(d[i],i));
while(s.size()){
int u=s.begin()->se;s.erase(s.begin());
if(d[u]>dmx)dmx=d[u],pos=top;
stk[++top]=u;
del.push_back(u);
ban[u]=1;
for(ri i=head[u];i;i=nxt[i]){
int v=to[i];
if(ban[v])continue;
s.erase(pi(d[v],v));
stk[++top]=v;
ban[v]=1;
delet(v);
}
}
cout<<n-pos;for(ri i=pos+1;i<=n;++i)cout<<' '<<stk[i];cout<<'\n';
cout<<del.size();for(ri i=del.size()-1;i>=0;--i)cout<<' '<<del[i];cout<<'\n';
}
signed main(){
// freopen("data.in","r",stdin);
int T=in;
while(T--)solve();
return 0;
}