舞动的夜晚

求二分图的不可行边

对于完备匹配的二分图来说:
如果我们把匹配边看做从右向左的单向边,其他边看做是从左向右的单向边 那么在图上行走的过程就是一条增广路
必须边:

  1. (x,y)匹配
  2. 去掉(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;
}
posted @ 2022-02-12 11:32  __iostream  阅读(34)  评论(0)    收藏  举报