最短路 & 最大流 -- Marriage Match IV HDU - 3416

Marriage Match IV HDU - 3416
题目大意:让你找出有多少条没有交集的最短路。

思路:先用spfa找出可行的边,然后给每条可行的边加上容量1.即表示这条边只能走一次。

接下来跑一遍ISAP就可以得出答案。

关于判断边可行的方法如下。

先从头跑一遍spfa,得到起点到其他所有点的最短路径dis1

再从尾跑一遍spfa,得到终点到其他所有点的最短路径dis2

对于边u-v w

假如dis1[u]+dis2[v]+w==dis1[终点]这可以得出结论,u-v这条边在一条最短路上。然后给这条边加上容量一。

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e3 + 5, M = 2e5 + 5, INF = 2e9;
struct E {
	int v, w, next;
} e[M], we[M]; //we保存网络流的图
int cas, n, m, s, t, u[M], v[M], w[M], len, wlen, h[N], rh[N], wh[N], d[N], rd[N], de[N];
bool vis[N]; 
//求2次最短路 
void add(int h[], int u, int v, int w) {
	e[++len].v = v;e[len].w = w;e[len].next = h[u];h[u] = len;
}
void wadd(int h[], int u, int v, int w) {
	we[++wlen].v = v;we[wlen].w = w;we[wlen].next = h[u];h[u] = wlen;
}
void spfa(int h[], int d[], int s) {
	memset(d, 0x3f, (n + 1) * sizeof(int));
	d[s] = 0;
	queue<int> q;
	q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		vis[u] = false;
		for (int j = h[u]; j; j = e[j].next) {
			int v = e[j].v;
			int w = e[j].w + d[u];
			if (d[v] > w) {
				d[v] = w;
				if (!vis[v]) q.push(v), vis[v] = true;
			}
		}
	}
} 
bool bfs() { //通过残量网络构建出分层图 
	memset(de, 0, (n + 1) * sizeof(int));
	de[s] = 1;                
	queue<int> q;    
	q.push(s);   
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int j = wh[u]; j; j = we[j].next) {
			int v = we[j].v;
			if (we[j].w && !de[v]) {
				de[v] = de[u] + 1;
				q.push(v);
				if (v == t) return 1;
			}
		}
	}
	return 0;
}
int dinic(int u, int flow) {
	if (u == t) return flow;
	int rest = flow, k;
	for (int j = wh[u]; j && rest; j = we[j].next) {
		int v = we[j].v;
		if (we[j].w && de[v] == de[u] + 1) {
			k = dinic(v, min(rest, we[j].w));
			if (!k) de[v] = 0;
			we[j].w -= k;			
			we[j ^ 1].w += k;
			rest -= k; 
		}
	}
	return flow - rest;
}
int main() {
	scanf("%d", &cas);
	while (cas--) {
		memset(h, 0, sizeof(h)); len = 0;
		memset(rh, 0, sizeof(rh));
		memset(wh, 0, sizeof(wh));wlen = 1;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%d", &u[i], &v[i], &w[i]);    
			if (u[i] == v[i]) continue; 
			add(h, u[i], v[i], w[i]);
			add(rh, v[i], u[i], w[i]); //反向边 
		} 
		scanf("%d%d", &s, &t);
		spfa(h, d, s); //2次最短路 
		spfa(rh, rd, t);
		//构建网络图 保存最短路的边 并设置流量为1
		for (int i = 1; i <= m; i++) {
			int a = u[i], b = v[i], c = w[i];
			if (a != b && d[a] + c + rd[b] == d[t]) {
				wadd(wh, a, b, 1); wadd(wh, b, a, 0);
			} 
		}
		//求s-->t的最大流 
		int ans = 0, flow; 
		while (bfs()) {
			while (flow = dinic(s, INF)) ans += flow;
		} 
		printf("%d\n", ans);
	}
	return 0; 
} 
发布了92 篇原创文章 · 获赞 7 · 访问量 3736

猜你喜欢

转载自blog.csdn.net/dajiangyou123456/article/details/104275924
今日推荐