HDU3416 Marriage Match IV 最短路 + 最大流

一、内容

 Do not sincere non-interference。
Like that show, now starvae also take part in a show, but it take place between city A and B. Starvae is in city A and girls are in city B. Every time starvae can get to city B and make a data with a girl he likes. But there are two problems with it, one is starvae must get to B within least time, it's said that he must take a shortest path. Other is no road can be taken more than once. While the city starvae passed away can been taken more than once.


So, under a good RP, starvae may have many chances to get to city B. But he don't know how many chances at most he can make a data with the girl he likes . Could you help starvae? 

Input

The first line is an integer T indicating the case number.(1<=T<=65)
For each case,there are two integer n and m in the first line ( 2<=n<=1000, 0<=m<=100000 ) ,n is the number of the city and m is the number of the roads.

Then follows m line ,each line have three integers a,b,c,(1<=a,b<=n,0<c<=1000)it means there is a road from a to b and it's distance is c, while there may have no road from b to a. There may have a road from a to a,but you can ignore it. If there are two roads from a to b, they are different.

At last is a line with two integer A and B(1<=A,B<=N,A!=B), means the number of city A and city B.
There may be some blank line between each case.

Output

Output a line with a integer, means the chances starvae can get at most.

Sample Input

3
7 8
1 2 1
1 3 1
2 4 1
3 4 1
4 5 1
4 6 1
5 7 1
6 7 1
1 7

6 7
1 2 1
2 3 1
1 3 3
3 4 1
3 5 1
4 6 1
5 6 1
1 6

2 2
1 2 1
1 2 2
1 2

Sample Output

2
1
1

二、思路

  • 题目求从s到t的最短路条数。 但和普通的最短路条数不同,这里每条边只能用一次。
  • 那么我们可以找出最短路径相关的边,利用这些边建立一个容量为1的网络流图,求s到t的最大流即是最短路的条数
  • 找出最短路的边: 判断一条边是不是最短路
    • s到该点的最短路d[u] + u–>v的边权w + v到t的最短路 == s到t的最短路。 如果相等代表这条边必须使用。
    • 那么就建立容量为1的边权。
  • 最后用 Dinic求一下最大流即可。

三、代码

#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; 
} 
发布了414 篇原创文章 · 获赞 380 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104213144
今日推荐