luogu3731 新型城市化
阿新 • • 發佈:2019-02-07
inf 題意 node 題目 滿足 ont turn mes max 一遍。再遍歷所有邊,找出那些不在兩段不在同一個強連通分量中,並且滿流的邊。
題目鏈接
思路
這道題對於題意的轉化很關鍵。
題目要求的是添上一條邊,使得圖中最大團的大小變大。給出的邊是原圖的補集,這就給我們了提示。
因為題目中說,原圖中最多有兩個團。所以給出的邊一定形成了一個二分圖。
那麽最大團就是新圖中的最大獨立集。
那麽問題就轉化成了,在新圖中刪除一條邊,使得新圖中的最大獨立集變大。
因為最大獨立集 = 點數-最大匹配。
所以我們要讓最大匹配變小。
考慮刪除哪些邊會讓最大匹配變小。首先肯定要在跑完網絡流之後是滿流的。然後不能由其他的邊來代替。也就是說在殘余網絡上跑一遍\(tarjan\),滿足兩段不在同一個強聯通分量中的邊。
所以做法也就出來了。先建圖跑一遍網絡流,然後在殘余網絡上\(tarjan\)
代碼
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<cstdlib> #include<cmath> #include<ctime> #include<algorithm> #include<bitset> using namespace std; typedef long long ll; #define change(x) x & 1 ? x + 1 : x - 1 const int M = 600010,N = 10010,INF = 1e9 + 7; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } struct node { int u,v,nxt,w; }e[M << 1],E[M << 1],ans[M << 1]; int anss; int head[N],ejs; void add(int u,int v,int w) { e[++ejs].u = u;e[ejs].v = v;e[ejs].w = w;e[ejs].nxt = head[u];head[u] = ejs; e[++ejs].u = v;e[ejs].v = u;e[ejs].w = 0;e[ejs].nxt = head[v];head[v] = ejs; } void ADD(int u,int v) { E[++ejs].u = u;E[ejs].v = v;E[ejs].nxt = head[u];head[u] = ejs; E[++ejs].v = u;E[ejs].u = v;E[ejs].nxt = head[v];head[v] = ejs; } int n,m,S,T; int lb[N]; void con(int u) { for(int i = head[u];i;i = E[i].nxt) { int v = E[i].v; if(lb[v]) continue; lb[v] = 3 - lb[u]; con(v); } } int dep[N],dfn[N],inque[N],sta[N],top,low[N],cnt,col[N],coljs; void tarjan(int u) { dfn[u] = low[u] = ++cnt; sta[++top] = u;inque[u] = 1; for(int i = head[u];i;i = e[i].nxt) { int v = e[i].v; if(e[i].w <= 0) continue; if(!dfn[v]) tarjan(v),low[u] = min(low[u],low[v]); else if(inque[v]) low[u] = min(low[u],low[v]); } if(low[u] == dfn[u]) { ++coljs; while(sta[top + 1] != u) { inque[sta[top]] = 0; col[sta[top--]] = coljs; } } } queue<int>q; int bfs() { memset(dep,0,sizeof(dep)); while(!q.empty()) q.pop(); q.push(S);dep[S] = 1; while(!q.empty()) { int u = q.front();q.pop(); for(int i = head[u];i;i = e[i].nxt) { int v = e[i].v; if(dep[v] || e[i].w <= 0) continue; dep[v] = dep[u] + 1; if(v == T) return 1; q.push(v); } } return 0; } int dfs(int u,int now) { if(u == T) return now; int re = 0; for(int i = head[u];i;i = e[i].nxt) { int v = e[i].v; if(e[i].w <= 0 || dep[v] != dep[u] + 1) continue; int k = dfs(v,min(now,e[i].w)); if(k) { e[i].w -= k; e[change(i)].w += k; now -= k; re += k; if(!now) break; // return k; } } return re; } void dinic() { while(bfs()) { int k = dfs(S,INF); while(k) { k = dfs(S,INF); } } } bool tmp(node X,node Y) { int k1 = min(X.u,X.v),t1 = max(X.u,X.v),k2 = min(Y.u,Y.v),t2 = max(Y.u,Y.v); return k1 == k2 ? t1 < t2 : k1 < k2; } int main() { n = read(),m = read(); for(int i = 1;i <= m;++i) { int u = read(),v = read(); ADD(u,v); } for(int i = 1;i <= n;++i) if(!lb[i]) lb[i] = 1,con(i); memset(head,0,sizeof(head)); ejs = 0; S = n + 1,T = S + 1; for(int i = 1;i <= n;++i) { if(lb[i] == 1) add(S,i,1); else add(i,T,1); } for(int i = 1;i <= m * 2;i += 2) { if(lb[E[i].u] == 1) add(E[i].u,E[i].v,1); else add(E[i].v,E[i].u,1); } dinic(); for(int i = 1;i <= n;++i) if(!dfn[i]) tarjan(i); for(int i = 1;i <= ejs;i += 2) { int u = e[i].u,v = e[i].v; if(col[u] != col[v] && e[i].w == 0 && e[i].u <= n &&e[i].v <= n) { ans[++anss] = e[i]; } } printf("%d\n",anss); sort(ans + 1,ans + anss + 1,tmp); for(int i = 1;i <= anss;++i) { printf("%d %d\n",min(ans[i].u,ans[i].v),max(ans[i].u,ans[i].v)); } return 0; }
luogu3731 新型城市化