HAOI2017 新型城市化 二分图的最大独立集+最大流+强连通缩点

题目链接(洛谷):https://www.luogu.org/problemnew/show/P3731

 

题意概述:给出一张二分图,询问删掉哪些边之后可以使这张二分图的最大独立集变大。N<=10000,0<=M<=min (150000,N(N-1)/2).

 

这个题首先你得总结出题意就是这个样子不然就是凉的。。。。。

二分图的最大独立集,可以想到网络流完成(定理:二分图的最大独立集=二分图点数-二分图最大匹配)。当最小割边小的时候独立集就变大了,因此问题变删掉哪些边可以让最小割变小。

这个问题就有经典的做法:先求出最小割,然后在残量网络上面跑tarjan强连通缩点,考察所有的满流的边,如果一条边满流并且两个端点不在同一个强连通分量中,那么这条边就存在与某个最小割中,删掉之后就相当于没有花代价把这条边割掉了,使得最小割变小(最大流变大)。

简单证明:

必要性:首先某一条边如果不满流,那么一定不是最小割中的边;如果一条满流边的反向边(它包含在残量网络中)在某个强连通分量中则可以视作给这条边找到了一个退流的方法,使得这条边(原图中)的起点处的流量可以绕过这条边到达这条边的终点。由于最小割是割掉之后源点汇点无法流通,这条边也显然不在最小割中。

充分性:当一条边满流并且反向边不在一个残量网络的强连通分量中的时候,这条边可能在最小割中,又由于这条边的反向边不在强连通分量中,我们没有办法找到一种方案使得这条边上的流量退去之后源点到汇点的流量不变。因此这条边一定在某个最小割之中,当这条边割掉之后,就相当于采用了这个最小割的方案,最小割变小。

 

注意一下一开始的建图,现在无向图上跑二分图确定好集合,如果用网络流跑二分图一定要注意连边必须是有向边,不然你会发现无向二分图跑最小流根本就不是匹配的意义。。。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 using namespace std;
 13 const int MAXN=150005;
 14 
 15 int N,M;
 16 struct data{
 17     int a,b;
 18     friend bool operator < (data x,data y){
 19         return x.a<y.a||x.a==y.a&&x.b<y.b;
 20     }
 21 }D[MAXN]; int ans;
 22 struct graph{
 23     static const int maxn=10005;
 24     static const int maxm=150005;
 25     struct edge{ int to,next; }E[maxm<<1];
 26     int first[maxn],np,color[maxn];
 27     graph(){ np=0; }
 28     void add_edge(int u,int v){
 29         E[++np]=(edge){v,first[u]};
 30         first[u]=np;
 31     }
 32     void DFS(int i,int c){
 33         color[i]=3-c;
 34         for(int p=first[i];p;p=E[p].next){
 35             int j=E[p].to;
 36             if(color[j]) continue;
 37             DFS(j,color[i]);
 38         }
 39     }
 40 }gp;
 41 struct NET{
 42     static const int maxn=10005;
 43     static const int maxm=150005;
 44     static const int inf=1e6;
 45     struct edge{ int from,to,next,cap,flow; }E[(maxm+maxn*2)<<1];
 46     int S,T,tot,first[maxn],np,cur[maxn],fl[maxn],d[maxn],gap[maxn];
 47     int dfn[maxn],low[maxn],dfs_clock,sccno[maxn],scc_cnt,stk[maxn],top;
 48     NET(){ np=dfs_clock=scc_cnt=0; }
 49     void add_edge(int u,int v,int c){
 50         E[++np]=(edge){u,v,first[u],c,0};
 51         first[u]=np;
 52         E[++np]=(edge){v,u,first[v],0,0};
 53         first[v]=np;
 54     }
 55     void BFS(){
 56         queue<int>q;
 57         for(int i=1;i<=tot;i++) d[i]=tot;
 58         d[T]=0; q.push(T);
 59         while(!q.empty()){
 60             int i=q.front(); q.pop();
 61             for(int p=first[i];p;p=E[p].next){
 62                 int j=E[p].to;
 63                 if(d[j]==tot) d[j]=d[i]+1,q.push(j);
 64             }
 65         }
 66     }
 67     int augment(){
 68         int now=T,flow=inf;
 69         while(now!=S){
 70             flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
 71             now=E[fl[now]].from;
 72         }
 73         now=T;
 74         while(now!=S){
 75             E[fl[now]].flow+=flow,E[(fl[now]-1^1)+1].flow-=flow;
 76             now=E[fl[now]].from;
 77         }
 78         return flow;
 79     }
 80     int ISAP(){
 81         memcpy(cur,first,sizeof(first));
 82         BFS();
 83         for(int i=1;i<=tot;i++) gap[d[i]]++;
 84         int now=S,flow=0;
 85         while(d[S]<tot){
 86             if(now==T) flow+=augment(),now=S;
 87             bool ok=0;
 88             for(int p=cur[now];p;p=E[p].next){
 89                 int j=E[p].to;
 90                 if(E[p].cap>E[p].flow&&d[j]+1==d[now]){
 91                     ok=1,cur[now]=fl[j]=p,now=j;
 92                     break;
 93                 }
 94             }
 95             if(!ok){
 96                 int minl=tot;
 97                 for(int p=first[now];p;p=E[p].next){
 98                     int j=E[p].to;
 99                     if(E[p].cap>E[p].flow&&d[j]+1<minl) minl=d[j]+1;
100                 }
101                 if(--gap[d[now]]==0) break;
102                 gap[d[now]=minl]++;
103                 cur[now]=first[now];
104                 if(now!=S) now=E[fl[now]].from;
105             }
106         }
107         return flow;
108     }
109     void tarjan_scc(int i){
110         dfn[i]=low[i]=++dfs_clock;
111         stk[++top]=i;
112         for(int p=first[i];p;p=E[p].next){
113             if(E[p].cap==E[p].flow) continue;
114             int j=E[p].to;
115             if(dfn[j]){
116                 if(!sccno[j]) low[i]=min(low[i],dfn[j]);
117                 continue;
118             }
119             tarjan_scc(j);
120             low[i]=min(low[i],low[j]);
121         }
122         if(low[i]==dfn[i]){
123             scc_cnt++;
124             while(stk[top]!=i) sccno[stk[top--]]=scc_cnt;
125             sccno[stk[top--]]=scc_cnt;
126         }
127     }
128 }net;
129 
130 void data_in()
131 {
132     scanf("%d%d",&N,&M);
133     int x,y;
134     net.S=N+1,net.T=N+2,net.tot=N+2;
135     for(int i=1;i<=M;i++){
136         scanf("%d%d",&x,&y);
137         gp.add_edge(x,y); gp.add_edge(y,x);
138     }
139     for(int i=1;i<=N;i++)
140         if(!gp.color[i]) gp.DFS(i,2);
141     for(int i=1;i<=M*2;i+=2){
142         x=gp.E[i].to,y=gp.E[i+1].to;
143         if(gp.color[x]==1) net.add_edge(x,y,1);
144         else net.add_edge(y,x,1);
145     }
146     for(int i=1;i<=N;i++){
147         if(gp.color[i]==1) net.add_edge(net.S,i,1);
148         else net.add_edge(i,net.T,1);
149     }
150 }
151 void work()
152 {
153     net.ISAP();
154     for(int i=1;i<=net.tot;i++)
155         if(!net.dfn[i]) net.tarjan_scc(i);
156     for(int i=1;i<=2*M;i++){
157         if(net.E[i].cap>net.E[i].flow||net.E[i].flow==0) continue;
158         int x=net.E[i].from,y=net.E[i].to;
159         if(net.sccno[x]!=net.sccno[y])
160             D[++ans]=(data){min(x,y),max(x,y)};
161     }
162     sort(D+1,D+ans+1);
163     printf("%d\n",ans);
164     for(int i=1;i<=ans;i++)
165         printf("%d %d\n",D[i].a,D[i].b);
166 }
167 int main()
168 {
169     data_in();
170     work();
171     return 0;
172 }

 

posted @ 2018-03-12 16:32  KKKorange  阅读(523)  评论(0编辑  收藏  举报