舞动的夜晚
求二分图的不可行边
对于完备匹配的二分图来说:
如果我们把匹配边看做从右向左的单向边,其他边看做是从左向右的单向边 那么在图上行走的过程就是一条增广路
必须边:
- (x,y)匹配
- 去掉(x,y) x不可达y
即在两个强联通分量中
可行边:
在同一个强联通分量中
对于一般的二分图 我们可以通过汇点来构建强联通分量 也就是在残量网络上求强联通分量
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define pa pair<int,int>
#define mp make_pair
using namespace std;
const int N=20005;
const int M=100005;
const int INF=0x3f3f3f3f;
int read()
{
int x=0,f=0,c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f?-x:x;
}
struct Edge
{
int to,next,w;
}e[M*2+N*4];
int head[N],cnt=1;
void _add(int a,int b,int c){ e[++cnt]=(Edge){b,head[a],c}; head[a]=cnt;}
void add(int a,int b,int c){ _add(a,b,c);_add(b,a,0);}
int d[N],p[M];
queue<int> q;
int n,m,t,S,T;
bool bfs()
{
while(q.size()) q.pop();
memset(d,0,sizeof d);
q.push(S); d[S]=1;
while(q.size())
{
int x=q.front(); q.pop();
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(d[y]||!e[i].w) continue;
d[y]=d[x]+1; q.push(y);
if(y==T) return true;
}
}
return false;
}
int dinic(int x,int flow)
{
if(x==T) return flow;
int rest=flow;
for(int i=head[x];i&&rest;i=e[i].next)//及时剪枝
{
int y=e[i].to;
if(e[i].w&&d[y]==d[x]+1)
{
int k=dinic(y,min(rest,e[i].w));
if(!k) d[y]=0;
e[i].w-=k; e[i^1].w+=k; rest-=k;
}
}
return flow-rest;
}
int dfn[N],low[N],sta[N],bel[N],tim,top,num;
bool ins[N];
void tarjan(int x)
{
dfn[x]=low[x]=++tim;
sta[++top]=x; ins[x]=1;
for(int i=head[x];i;i=e[i].next)
{
if(!e[i].w) continue;
int y=e[i].to;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
int z; num++;
do
{
z=sta[top]; top--;
bel[z]=num; ins[z]=0;
}while(z!=x);
}
}
int ret[N],tot;
int main()
{
n=read(); m=read(); t=read();
for(int i=1;i<=t;i++)
{
int x=read(),y=read();
p[i]=cnt+1;
add(x,y+n,1);
}
S=n+m+1; T=n+m+2;
for(int i=1;i<=n;i++) add(S,i,1);
for(int i=n+1;i<=n+m;i++) add(i,T,1);
int maxflow=0,flow=0;
while( bfs() )
while(flow=dinic(S,INF)) maxflow+=flow;//cout<<flow<<endl;
for(int x=1;x<=n;x++)
if(!dfn[x]) tarjan(x);
for(int i=1;i<=t;i++)
{
int x=e[ p[i] ].to,y=e[ p[i]^1].to;
if( e[ p[i] ].w &&bel[x]!=bel[y]) ret[++tot]=i;
}
printf("%d\n",tot);
for(int i=1;i<=tot;i++) printf("%d ",ret[i]);
return 0;
}

浙公网安备 33010602011771号