LOJ2276 [HAOI2017] 新型城市化 【二分图匹配】【tarjan】

题目分析:

这题出的好!

首先问题肯定是二分图的最大独立集,如果删去某条匹配边之后独立集是否会变大。

跑出最大流之后流满的边就是匹配边。

如果一个匹配边的两个端点在一个强连通分量里,那这条边删掉之后我们就可以找到一个替代方案使得匹配不变小。

具体的,假设这两个点是x,y。因为两者之间连的是匹配边,那么存在一个路径从t->y->x->s。那只要从s有另一条路径到y或者从x有另一条路径到t那就构成一个强连通分量,我们只考虑s到y的情况。

如果存在一条这样的路,我们会发现每次从X集合跳到Y集合的时候走的是黑边,从Y集合跳到X集合的时候走的是红遍,因为我们的目标节点在Y集合,所以采用匈牙利树的分析方法,黑边总比红边多1,所以可以把这条路径翻转达到我们的目的。

 

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxm = 400000,maxn = 20300;
  5 
  6 struct edge{int from,to,flow;}edges[maxm];
  7 int num,n,m,arr[maxn];
  8 vector <int> g[maxn];
  9 int color[maxn];
 10 
 11 namespace BioGraph{
 12     vector<int> T[maxn];
 13     queue<int> Q;
 14     void pd(){
 15     for(int i=1;i<=n;i++){
 16         if(arr[i]) continue;
 17         Q.push(i); arr[i] = 1; color[i] = 0;
 18         while(!Q.empty()){
 19         int k = Q.front(); Q.pop();
 20         for(int i=0;i<T[k].size();i++){
 21             int z = T[k][i];
 22             if(arr[z]) continue;
 23             Q.push(z); color[z] = (color[k]^1); arr[z] = 1;
 24         }
 25         }
 26     }
 27     }
 28 }
 29 namespace SCC{
 30     int dfn[maxn],low[maxn],scc[maxn],sccnum,cl;
 31     stack<int> sta;
 32     void Tarjan(int now){
 33     low[now] = dfn[now] = ++cl;
 34     sta.push(now);
 35     for(int i=0;i<g[now].size();i++){
 36         if(edges[g[now][i]].flow == 0) continue;
 37         int to = edges[g[now][i]].to;
 38         if(arr[to]) continue;
 39         if(dfn[to]) low[now] = min(low[now],dfn[to]);
 40         else{Tarjan(to);low[now] = min(low[now],low[to]);}
 41     }
 42     if(low[now]==dfn[now]){
 43         sccnum++;
 44         while(true){
 45         int pi = sta.top(); sta.pop();
 46         arr[pi] = 1; scc[pi] = sccnum;
 47         if(now == pi) break;
 48         }
 49     }
 50     }
 51 }
 52 
 53 void AddEdge(int x,int y,int v){
 54     edges[num++] = (edge){x,y,v};
 55     edges[num++] = (edge){y,x,0};
 56     g[x].push_back(num-2);
 57     g[y].push_back(num-1);
 58 }
 59 
 60 int dis[maxn],cur[maxn];
 61 queue<int> qq; 
 62 int BFS(){
 63     qq.push(0); memset(dis,-1,sizeof(dis)); dis[0] = 1;
 64     while(!qq.empty()){
 65     int k = qq.front(); qq.pop();
 66     for(int i=0;i<g[k].size();i++){
 67         edge sm = edges[g[k][i]];
 68         if(sm.flow && dis[sm.to]== -1){
 69         dis[sm.to] = dis[k]+1;
 70         qq.push(sm.to);
 71         }
 72     }
 73     }
 74     return dis[n+1];
 75 }
 76 
 77 int dfs(int x,int a){
 78     if(x == n+1 || a == 0) return a;
 79     int flow = 0,f;
 80     for(int &i=cur[x];i<g[x].size();i++){
 81     edge &xx = edges[g[x][i]];
 82     if(dis[xx.to]>dis[x]&&(f=dfs(xx.to,min(a,xx.flow)))){
 83         xx.flow -= f;
 84         flow += f;
 85         a -= f;
 86         edges[g[x][i]^1].flow+=f;
 87         if(a == 0) return flow;
 88     }
 89     }
 90     return flow;
 91 }
 92 
 93 void read(){
 94     scanf("%d%d",&n,&m);
 95     for(int i=1;i<=m;i++){
 96     int x,y; scanf("%d%d",&x,&y);
 97     BioGraph::T[x].push_back(y);
 98     BioGraph::T[y].push_back(x);
 99     }
100     BioGraph::pd();
101     for(int i=1;i<=n;i++){
102     if(color[i]) {AddEdge(i,n+1,1);continue;}
103     else AddEdge(0,i,1);
104     for(int j=0;j<BioGraph::T[i].size();j++){
105         int z = BioGraph::T[i][j];
106         AddEdge(i,z,1);
107     }
108     }
109 }
110 
111 vector<pair<int,int> > res;
112 void work(){
113     int flow = 0;
114     while(BFS() != -1){
115     memset(cur,0,sizeof(cur));
116     flow += dfs(0,19260817);
117     }
118     memset(arr,0,sizeof(arr));
119     for(int i=0;i<=n+1;i++){
120     if(arr[i]) continue;
121     SCC::Tarjan(i);
122     }
123     for(int i=0;i<num;i++){
124     if(edges[i].from == 0 || edges[i].to == n+1) continue;
125     if(edges[i].from == n+1 || edges[i].to == 0) continue;
126     if(color[edges[i].from]) continue;
127     if(edges[i].flow) continue;
128     if(SCC::scc[edges[i].from] == SCC::scc[edges[i].to]) continue;
129     int x=min(edges[i].from,edges[i].to),y=max(edges[i].from,edges[i].to);
130     res.push_back(make_pair(x,y));
131     }
132     sort(res.begin(),res.end());
133     int z = res.size(); printf("%d\n",z);
134     for(int i=0;i<z;i++){ printf("%d %d\n",res[i].first,res[i].second); }
135 }
136 
137 int main(){
138     read();
139     work();
140     return 0;
141 }

 

posted @ 2019-03-15 15:20  menhera  阅读(271)  评论(0编辑  收藏  举报