题目链接(洛谷):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 ",ans); 164 for(int i=1;i<=ans;i++) 165 printf("%d %d ",D[i].a,D[i].b); 166 } 167 int main() 168 { 169 data_in(); 170 work(); 171 return 0; 172 }