链接:http://cogs.pro/cogs/problem/problem.php?pid=426
题意:在二分图中找出一类边的数量,这类边的特点是:砍掉这条边之后整个二分图最大匹配数量减少。
首先跑一个裸的二分图最大匹配,找到所有的连接方式。可能有人会认为最大匹配数就是所求结果,但其实不是,因为我们可以举出一个例子:
在这张图中,最大匹配数是1,但是显然种类是0种,因此我们还需要想其他的思路。
以样例为例,考虑跑完二分图匹配之后的增广路:
其中,虚线表示增广后的反向边。我们可以看出有些点是在同一个强连通分量上的,砍掉这些点之间的边毫无意义。
因此思路就出来了:跑完二分图最大匹配后在残量网络上尬舞跑Tarjan,搞出强连通分量,随后枚举每一条被增广的边,如果起点终点在同一强连通分量内,ans--。
问题得解。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=200005; 7 struct node 8 { 9 int from,to,flow,next; 10 }edge[maxn<<1]; 11 int head[maxn],tot; 12 void addedge(int u,int v,int w) 13 { 14 edge[tot]=(node){u,v,w,head[u]};head[u]=tot++; 15 edge[tot]=(node){v,u,0,head[v]};head[v]=tot++; 16 } 17 int n,m,S,T,exist[maxn]; 18 #include<queue> 19 const int inf=0x7fffffff; 20 int dis[maxn]; 21 bool bfs() 22 { 23 memset(dis,0,sizeof(dis)); 24 dis[S]=1; 25 queue<int>q;q.push(S); 26 while(!q.empty()) 27 { 28 int u=q.front();q.pop(); 29 for(int i=head[u];i!=-1;i=edge[i].next) 30 { 31 int v=edge[i].to; 32 if(!dis[v]&&edge[i].flow>0) 33 { 34 dis[v]=dis[u]+1; 35 q.push(v); 36 } 37 } 38 } 39 return dis[T]!=0; 40 } 41 int dfs(int pos,int flow) 42 { 43 if(pos==T||!flow)return flow; 44 int ans=0; 45 for(int i=head[pos];i!=-1;i=edge[i].next) 46 { 47 int v=edge[i].to; 48 if(dis[v]==dis[pos]+1&&edge[i].flow>0) 49 { 50 int t=dfs(v,min(flow,edge[i].flow)); 51 if(t) 52 { 53 edge[i].flow-=t; 54 edge[i^1].flow+=t; 55 ans+=t; 56 if(ans==flow)break; 57 } 58 } 59 } 60 return ans; 61 } 62 int dfn[maxn],low[maxn],cnt,scnt,belong[maxn],instack[maxn]; 63 #include<stack> 64 stack<int>s; 65 void dfs(int pos) 66 { 67 dfn[pos]=low[pos]=++cnt;s.push(pos);instack[pos]=1; 68 for(int i=head[pos];i!=-1;i=edge[i].next) 69 { 70 int v=edge[i].to; 71 if(edge[i].flow>0) 72 { 73 if(!dfn[v]) 74 { 75 dfs(v); 76 low[pos]=min(low[pos],low[v]); 77 } 78 else if(instack[v])low[pos]=min(low[pos],dfn[v]); 79 } 80 } 81 if(low[pos]==dfn[pos]) 82 { 83 scnt++;int k; 84 do 85 { 86 k=s.top();s.pop(); 87 belong[k]=scnt; 88 instack[k]=0; 89 }while(k!=pos); 90 } 91 } 92 int haha() 93 { 94 freopen("bloodsail.in","r",stdin); 95 freopen("bloodsail.out","w",stdout); 96 memset(head,-1,sizeof(head)); 97 scanf("%d%d",&n,&m); 98 for(int i=1;i<=m;i++) 99 { 100 int x,y;scanf("%d%d",&x,&y); 101 addedge(x,y,1); 102 exist[x]=exist[y]=1; 103 } 104 S=0,T=n+1; 105 int mid=n>>1; 106 for(int i=1;i<=mid;i++) 107 if(exist[i])addedge(S,i,1); 108 for(int i=mid+1;i<=n;i++) 109 if(exist[i])addedge(i,T,1); 110 int ans=0; 111 while(bfs()) 112 ans+=dfs(S,inf); 113 for(int i=1;i<=n;i++) 114 if(!dfn[i])dfs(i); 115 for(int i=1;i<=mid;i++) 116 for(int j=head[i];j!=-1;j=edge[j].next) 117 { 118 int v=edge[j].to; 119 if(!edge[j].flow&&v&&belong[i]==belong[v])ans--; 120 } 121 printf("%d ",ans); 122 } 123 int sb=haha(); 124 int main(){;}