[AHOI2009]最小割

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/87865308

求可能在最小割的边和一定在最小割中的边。

1.判定边xy是否可能在最小割中 (最小割可行边)
充要条件:
  1.满流。
  2.在残余网络中找不到x到y的路径。
很好理解,如果还能找到,那么砍了它也没什么用
如果正向弧没流满,那么肯定不是最小割(可以找到另一条更好限制流量的边)
只有满流才能让正向弧等于0,才有不能找到的条件
因此,在算法体现中,他们两个必定只能不属于一个SCC才能在最小割中

2.判定边xy是否必然在最小割中
(最小割必须边)
充要条件:
  1.满流。
  2.残余网络中源点能到入点,出点能到汇点。
若满流但在残余网络中源点不能到入点或出点不能到汇点,
那么在每条单独路径上一定都存在一条满足最小割可行边的边
(一条容量为0的正向弧阻断路径且没有其他路径),
割掉这条可行边是可以起到同样的阻断效果同时代价更优的。
因此,在算法实现中,只有源点和x属于一个SCC,汇点和y属于一个SCC,才能达到割掉它属于最优解

AC Code:

#include<bits/stdc++.h>
#define maxn 10005
#define maxm 400005
#define inf 0x3f3f3f3f
using namespace std;

int n,m,S,T,x[maxm],y[maxm];
int info[maxn],Prev[maxm],to[maxm],cap[maxm],cnt_e=1;
inline void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c; }
inline void Line(int u,int v,int c){ Node(u,v,c),Node(v,u,0); }

int dis[maxn];
bool BFS()
{
	memset(dis,-1,sizeof dis);
	static queue<int>q;
	q.push(T),dis[T]=0;
	for(int now;!q.empty();)
	{
		now = q.front();q.pop();
		for(int i=info[now];i;i=Prev[i])
			if(cap[i^1] && dis[to[i]] == -1)
				dis[to[i]] = dis[now] + 1 , q.push(to[i]); 
	}
	return dis[S] != -1;
}

int aug(int now,int Max)
{
	if(now == T) return Max;
	int inc,st=Max;
	for(int i=info[now];i && st;i=Prev[i])
		if(cap[i] && dis[to[i]] == dis[now] - 1)
		{
			inc = aug(to[i],min(cap[i],st));
			st-=inc,cap[i]-=inc,cap[i^1]+=inc;
		}
	return Max-st;
}

int dfn[maxn],low[maxn],tot,scc,c[maxn];
stack<int>sta;
void dfs(int now)
{
	dfn[now]=low[now]=++tot;
	sta.push(now);
	for(int i=info[now];i;i=Prev[i])
		if(cap[i])
		{
			if(!dfn[to[i]]) dfs(to[i]),low[now]=min(low[now],low[to[i]]);
			else if(!c[to[i]]) low[now] = min(low[now] , dfn[to[i]]);
		}
	if(low[now] == dfn[now])
	{
		scc++;
		for(int tmp;;)
		{
			c[tmp=sta.top()] = scc;
			sta.pop();
			if(tmp == now) break;
		}
	}
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&S,&T);
	for(int i=1;i<=m;i++)
	{
		int c;
		scanf("%d%d%d",&x[i],&y[i],&c);
		Line(x[i],y[i],c);
	}
	
	for(;BFS();) aug(S,inf);
	
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			dfs(i);
			
	for(int i=1;i<=m;i++)
		printf("%d %d\n",c[x[i]]!=c[y[i]] && cap[2*i]==0,(c[x[i]]==c[S] && c[y[i]] == c[T]) && cap[2*i]==0);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/87865308