在洛谷题解逛了一圈,不是随机化乱搞就是带log的做法,这里来一个线性且正确性有保证的做法。
人傻常数大,打不过随机化/kk
洛谷
LibreOJ
做法是每次删除度最小的点,贪心加入独立集。因为很多题解都证过了,这里就不证正确性了。
讲一下实现。
我们对每个点按度数桶排,然后可以从小到大枚举 \(p\),每次删除度数不超过 \(p\) 的点并且动态更新度数,度数如果减小到删除条件就直接删掉,可以递归实现。
在删除过程中同样可以维护独立集,值得注意的是打独立集的 tag 的时候要先打再递归去删数,不然会出问题。
卡常技巧是不用 vector
而是用链表。
具体实现可以看代码。
//12252024832524 #include <bits/stdc++.h> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 10005; int n,m; char buf[1<<21],*p1=buf,*p2=buf; #define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) LL Read() { LL x = 0,f = 1;char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} int head[MAXN],tot,deg[MAXN],hd[MAXN]; struct edge{ int v,nxt; }e[MAXN*45]; void Add_Edge(int u,int v){ e[++tot] = edge{v,head[u]}; head[u] = tot; } void Add_Double_Edge(int u,int v){ Add_Edge(u,v); Add_Edge(v,u); ++deg[u]; ++deg[v]; } bool used[MAXN],del[MAXN]; int ans1[MAXN],ans2[MAXN],t1,t2,MAX; void clr(int x,int p){ del[x] = 1; ans1[++t1] = x; bool sg = 0; if(!used[x]) ans2[++t2] = x,used[x] = sg = 1; if(sg) for(int i = head[x]; i ;i = e[i].nxt) used[e[i].v] = 1;//先打tag for(int i = head[x],v; i ;i = e[i].nxt) {//后删数字 if(del[v = e[i].v]) continue; --deg[v]; if(deg[v] <= p) clr(v,p); else e[++tot] = edge{v,hd[deg[v]]},hd[deg[v]] = tot; } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); for(int T = Read(); T ;-- T){ n = Read(); m = Read(); t1 = t2 = tot = MAX = 0; for(int i = 0;i <= n;++ i) head[i] = deg[i] = hd[i] = used[i] = del[i] = 0; for(int i = 1;i <= m;++ i) Add_Double_Edge(Read(),Read()); for(int i = 1;i <= n;++ i) e[++tot] = edge{i,hd[deg[i]]},hd[deg[i]] = tot; for(int p = 0;p < n;++ p){ for(int i = hd[p]; i ;i = e[i].nxt){ int x = e[i].v; if(del[x]) continue; if(p > MAX) MAX = p,t1 = 0; clr(x,p); } } Put(t1,' '); for(int i = 1;i <= t1;++ i) Put(ans1[i],' '); putchar('\n'); Put(t2,' '); for(int i = 1;i <= t2;++ i) Put(ans2[i],' '); putchar('\n'); } return 0; }