HDU 3416 Marriage Match IV (最短路 + 最大流)

Problem Description

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

 

题目大意 : 输入一个有向图, 输出从起点到终点的最短路有多少条, 每条边只允许走一次

思路 :  首先跑一遍最短路, 将从起点到各个点之间的最短路给保存下来, 再跑一遍最短路, 并将所有 “可能构成最短路的边” 给存到新图中, 判定条件为:dis【v】== 已保存下来的最短路的值, 不清楚的可以自己画画图。 因为走过的边不能再走, 可以想到网络流就有这样的特点, 所以存新图的时候将权值置为1即可, 最后跑一遍最大流, 答案就出来了。

Accepted code

#include<bits/stdc++.h>
using namespace std;

#define sc scanf
#define mem memset
#define Min(a, b) a = min(a, b)
#define Max(a, b) a = max(a, b)
typedef long long ll;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int v, w, next;
}e[MAXN << 1], edge[MAXN << 1]; // e为最短路边, edge为最大流边
struct node
{
	int id, w;
	bool operator < (const node &oth) const
	{
		return w > oth.w;
	}
}mid;
int head[MAXN], pre[MAXN], cur[MAXN], n, m, cnt, T; // head和pre分别为链式前向星
int dis[MAXN], dist[MAXN], dep[MAXN], sp, tp, tot; // dist为保存的最短路
void init() {   
	mem(e, 0, sizeof(e));
	mem(pre, -1, sizeof(pre));
	mem(head, -1, sizeof(head));
	cnt = tot = 0;
}
void add(int from, int to, int dis) { // 最短路存边
	e[++cnt].v = to;
	e[cnt].w = dis;
	e[cnt].next = head[from];
	head[from] = cnt;
}
void Add(int from, int to, int wi) {  // 网络流存边
	edge[tot].v = to; edge[tot].next = pre[from];
	edge[tot].w = wi; pre[from] = tot++;

	edge[tot].v = from; edge[tot].next = pre[to];
	edge[tot].w = 0; pre[to] = tot++;
}
void dijkstra(int u) {  // 第一次最短路用来保存最短路径
	priority_queue <node> q;
	mem(dis, INF, sizeof(dis));
	dis[u] = 0;
	q.push({ u, 0 });
	mem(pre, -1, sizeof(pre));
	pre[u] = -1;
	while (!q.empty()) {
		mid = q.top();
		q.pop();
		int ans = mid.id;
		if (mid.w != dis[ans]) continue;
		for (int i = head[ans]; i != -1; i = e[i].next) {
			if (dis[e[i].v] > dis[ans] + e[i].w) {
				dis[e[i].v] = dis[ans] + e[i].w;
				q.push({ e[i].v, dis[e[i].v] });
			}
		}
	}
}
void dij(int u) {  // 第二遍最短路用来保存可以到终点路程最短的路径
	priority_queue <node> q;
	mem(dis, INF, sizeof(dis));
	dis[u] = 0;
	q.push({ u, 0 });
	mem(pre, -1, sizeof(pre));
	pre[u] = -1;
	while (!q.empty()) {
		mid = q.top();
		q.pop();
		int ans = mid.id;
		if (mid.w != dis[ans]) continue;
		for (int i = head[ans]; i != -1; i = e[i].next) { // 路径相同则存图
			if (dist[e[i].v] == dis[ans] + e[i].w) Add(ans, e[i].v, 1);
			if (dis[e[i].v] > dis[ans] + e[i].w) {
				dis[e[i].v] = dis[ans] + e[i].w;
				q.push({ e[i].v, dis[e[i].v] });
			}
		}
	}
}
bool bfs() { // 寻找增广路
	queue <int> q;
	mem(dep, 0, sizeof(dep));
	dep[sp] = 1, q.push(sp);
	while (!q.empty()) {
		int now = q.front();
		q.pop(); 
		for (int i = pre[now]; i != -1; i = edge[i].next) {
			int vi = edge[i].v;
			if (!dep[vi] && edge[i].w) {
				dep[vi] = dep[now] + 1;
				q.push(vi);
			}
		}
	}
	if (dep[tp]) return true;
	return false;
}
int dfs(int x, int d) { // 找流量
	if (x == tp || d == 0) return d;
	int res = 0, r;
	for (int &i = cur[x]; i != -1; i = edge[i].next) {
		int vi = edge[i].v;
		if (dep[vi] == dep[x] + 1 && edge[i].w) {
			r = dfs(vi, min(edge[i].w, d - res));
			if (r > 0) {
				edge[i].w -= r;
				edge[i ^ 1].w += r;
				res += r;
			}
		}
	}
	if (!res) dep[x] = 0;
	return res;
} 
int dinic() {
	int flow = 0, ans;
	while (bfs()) {
		for (int i = 1; i <= n; i++) cur[i] = pre[i];
		flow += dfs(sp, INF);
	}
	return flow;
}

int main()
{
	cin >> T;
	while (T--) {
		sc("%d %d", &n, &m);
		init();
		for (int i = 0; i < m; i++) {
			int ui, vi, wi;
			sc("%d %d %d", &ui, &vi, &wi);
			add(ui, vi, wi);
		}
		sc("%d %d", &sp, &tp);
		dijkstra(sp);
		for (int i = 1; i <= n; i++) dist[i] = dis[i]; // 备注最短路
		dij(sp);
		cout << dinic() << endl;
	}
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值