zoukankan      html  css  js  c++  java
  • 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
    ",z);
    134     for(int i=0;i<z;i++){ printf("%d %d
    ",res[i].first,res[i].second); }
    135 }
    136 
    137 int main(){
    138     read();
    139     work();
    140     return 0;
    141 }
  • 相关阅读:
    【BZOJ 4151 The Cave】
    【POJ 3080 Blue Jeans】
    【ZBH选讲·树变环】
    【ZBH选讲·拍照】
    【ZBH选讲·模数和】
    【CF Edu 28 C. Four Segments】
    【CF Edu 28 A. Curriculum Vitae】
    【CF Edu 28 B. Math Show】
    【CF Round 439 E. The Untended Antiquity】
    【CF Round 439 C. The Intriguing Obsession】
  • 原文地址:https://www.cnblogs.com/Menhera/p/10537311.html
Copyright © 2011-2022 走看看