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 }
  • 相关阅读:
    fastadmin的会员中心和cms插件,两者整合在一起。界面上怎么整合啊?
    thinkphp5框架中为啥要使用traits
    TP5三足鼎力的目录结构,以及相关的文件位置
    tp5 如何创建公共函数
    PSR4自动加载
    关于js中循环遍历中顺序执行ajax的问题(vue)
    laravel+vue+vuetify 前端匹配不到数据记录 No matching records found
    mysql表中时间timestamp设计
    基本语法
    leetcode——1382. 将二叉搜索树变平衡
  • 原文地址:https://www.cnblogs.com/Menhera/p/10537311.html
Copyright © 2011-2022 走看看