Mincut 最小割 HYSBZ - 1797

本文探讨了在A国与B国的战争背景下,如何利用最小割算法解决B国破坏A国物资运输网的问题。通过建立图模型,采用Dinic算法求解最小割,进而分析每条道路在最小割中的作用。文章深入解析了如何判断某条道路是否存在于最小割中,以及它是否对所有最小割都是必需的。

A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。

Input

第一行有4个正整数,依次为N,M,s和t。第2行到第(M+1)行每行3个正 整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v, 终点是u,切断它的代价是c(1≤c≤100000)。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。

Output

对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分 别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

思路:直接看大佬博客吧。。。。http://hzwer.com/3217.html

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 1e5 + 50;
int INF = 1e9;
struct Edge
{
	int u, to, next, w, id;
} edge[maxn], data[maxn];

int k, head[maxn];
int n, m;
void add(int a, int b, int c){
	edge[k].u = a;
	edge[k].to = b;
	edge[k].w = c;
	edge[k].next = head[a];
	head[a] = k++;

	edge[k].u = b;
	edge[k].to = a;
	edge[k].w = 0;
	edge[k].next = head[b];
	head[b] = k++;
}

int dis[maxn];
int bfs(int s, int t){
	queue<int> que;
	for(int i = 0; i <= n; i++){
		dis[i] = 0;
	}
	dis[s] = 1;
	que.push(s);
	while(que.size()){
		int u = que.front();
		que.pop();
		if(u == t){
			return 1;
		}
		for(int i = head[u]; i != -1; i = edge[i].next){
			int to = edge[i].to;
			int w = edge[i].w;
			if(!dis[to] && w){
				dis[to] = dis[u] + 1;
				if(to == t){
					return 1;
				}
				que.push(to);
			}
		}
	}
	return 0;
}

int cur[maxn];
int dfs(int u, int maxf, int t){
	if(u == t){
		return maxf;
	}
	int ret = 0;

	for(int i = cur[u]; i != -1; i = edge[i].next){
		cur[u] = i;
		int to = edge[i].to;
		int w = edge[i].w;
		if(w && dis[to] == dis[u] + 1){
			int mi = min(w, maxf - ret);
			w = dfs(to, mi, t);
			edge[i].w -= w;
			edge[i ^ 1].w += w;
			ret += w;
			if(ret == maxf){
				return ret;
			}
		}
	}
	return ret;
}

int Dinic(int s, int t){
	int ans = 0;
	while(bfs(s, t)){
		for(int i = 0 ; i <= n; i++){
			cur[i] = head[i];
		}
		ans += dfs(s, INF, t);
	}
	return ans;
}

void init(){
	k = 0;
	memset(head, -1, sizeof(head));
}

int dfn[maxn], low[maxn], ss[maxn], scc_id[maxn], in[maxn];
int tim, top, scc_cnt;
void Tarian(int u){
	dfn[u] = low[u] = ++tim;
	ss[++top] = u;
	in[u] = 1;
	for(int i = head[u]; i != -1; i = edge[i].next){
		if(edge[i].w == 0){
			continue;
		}
		int to = edge[i].to;

		if(!dfn[to]){
			Tarian(to);
			low[u] = min(low[u], low[to]);
		} else if(in[to]){
			low[u] = min(low[u], dfn[to]);
		}
	}

	if(low[u] == dfn[u]){
		int x;
		scc_cnt++;
		do{
			x = ss[top--];
			scc_id[x] = scc_cnt;
			in[x] = 0;
		} while(x != u);
	}
}
int main() {
	init();
	int s, t;
	scanf("%d%d%d%d", &n, &m, &s, &t);
	for(int i = 1; i <= m; i++){
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c);
		data[i].u = a;
		data[i].to =b;
	}

	int res = Dinic(s, t);
	for(int i = 1; i <= n; i++){
		if(scc_id[i] == 0){
			Tarian(i);
		}
	}

	for(int i = 0; i < k; i += 2){
		int u = edge[i].u;
		int to = edge[i].to;
		int ans1 = 0, ans2 =0;
		if(edge[i].w == 0){
			if(scc_id[u] != scc_id[to]){
				ans1 = 1;
				if((scc_id[u] == scc_id[s] && scc_id[to] == scc_id[t])){
					ans2 = 1;
				}
			}
		}
		printf("%d %d\n", ans1, ans2);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值