HDU - 6582 Path(spfa+最大流)

本文介绍了一种通过计算最短路径并利用最大流算法来阻止角色Jerry访问其女友家的有效方法。通过双向SPFA算法确定最短路径,并找出所有覆盖最短路径的边,再使用最大流算法确保角色无法通过原始最短路径到达目的地。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Years later, Jerry fell in love with a girl, and he often walks for a long time to pay visits to her. But, because he spends too much time with his girlfriend, Tom feels neglected and wants to prevent him from visiting her. 
After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly nn houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 11 and go along the shortest path to hers, indexed nn. 
Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl's home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer. 
Note, if Jerry can't reach his girl's house in the very beginning, the answer is obviously zero. And you don't need to guarantee that there still exists a way from Jerry's house to his girl's after blocking some edges.

Input

The input begins with a line containing one integer T(1≤T≤10)T(1≤T≤10), the number of test cases. 
Each test case starts with a line containing two numbers n,m(1≤n,m≤10000)n,m(1≤n,m≤10000), the number of houses and the number of one-way roads in the neighbourhood. 
mm lines follow, each of which consists of three integers x,y,c(1≤x,y≤n,1≤c≤109)x,y,c(1≤x,y≤n,1≤c≤109), denoting that there exists a one-way road from the house indexed xx to yy of length cc.

Output

Print TT lines, each line containing a integer, the answer.

Sample Input

1
3 4
1 2 1
2 3 1
1 3 2
1 3 3

Sample Output

3

            简而言之就是堵住一些路让之后的最短路比之前的最短路长~~

            首先双向spfa,这样的话假设这条边是对于一条路来说(u,v,w),假设(正向spfa后的dis[u])+(负向spfa后的udis[v])+w==最短路长度,那么就说明这条路是最短路的必经路之一。把所有的最短路径涵盖的边找出来之后跑最大流让最短路无法从1到n就好了~还有就是特判本来就无法到达的情况。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
struct fuck {
	int u, v, w, ne;
}ed[maxn], ued[maxn], wed[maxn];
long long dis[maxn], udis[maxn];
int head[maxn], uhead[maxn], cnt, ucnt, wcnt;
int whead[maxn], wdis[maxn], cur[maxn];
int n, m;
void add(int u, int v, int w, fuck ed[], int &cnt,int head[]) {
	ed[cnt].u = u; ed[cnt].v = v;
	ed[cnt].w = w; ed[cnt].ne = head[u]; head[u] = cnt++;
}
void addedge(int u, int v, int w) {
	wed[wcnt].v = v; wed[wcnt].w = w;
	wed[wcnt].ne = whead[u]; whead[u] = wcnt++;
	wed[wcnt].v = u, wed[wcnt].w = 0;
	wed[wcnt].ne = whead[v]; whead[v] = wcnt++;
}
int bfs(int st, int en) {
	queue<int>q;
	memset(wdis, 0, sizeof(wdis));
	wdis[st] = 1;
	q.push(st);
	while (!q.empty()) {
		int u = q.front(); q.pop();
		if (u == en)return 1;
		for (int s = whead[u]; ~s; s = wed[s].ne) {
			int v = wed[s].v;
			if (wdis[v] == 0 && wed[s].w > 0) {
				wdis[v] = wdis[u] + 1; q.push(v);
			}
		}
	}
	return wdis[en] != 0;
}
int dfs(int st, int en, int flow) {
	int ret = flow, a;
	if (st == en || flow == 0)return flow;
	for (int &s = cur[st]; ~s; s = wed[s].ne) {
		int v = wed[s].v;
		if (wdis[v] == wdis[st] + 1 && (a = dfs(v, en, min(ret, wed[s].w)))) {
			wed[s].w -= a;
			wed[s ^ 1].w += a;
			ret -= a;
			if (!ret)break;
		}
	}
	if (ret == flow)wdis[st] = 0;
	return flow - ret;
}
long long dinic(int st, int en) {
	long long ans = 0;
	while (bfs(st, en)) {
		for (int s = 0; s <= n; s++) //这里!!
			cur[s] = whead[s];
		ans += dfs(st, en, inf);
	}
	return ans;
}
void spfa(int st,long long dis[],int head[],fuck ed[]) {
	dis[st] = 0;
	queue<int>q;
	q.push(st);
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		for (int i = head[u]; ~i; i = ed[i].ne) {
			int v = ed[i].v;
			if (dis[v] > dis[u] + 1LL * ed[i].w) {
				dis[v] = dis[u] + 1LL * ed[i].w;
				q.push(v);
			}
		}
	}
	return;
}
int main() {
	int te;
	ios::sync_with_stdio(0);
	cin >> te;
	while (te--) {
		cin >> n >> m;
		for (int i = 0; i <= n; i++) {
			head[i] = uhead[i] = whead[i] = -1;
			dis[i] = udis[i] = INF;
		}
		ucnt = cnt = wcnt = 0;
		for (int i = 0; i < m; i++) {
			int a, b, c;
			cin >> a >> b >> c;
			add(a, b, c, ed, cnt, head);
			add(b, a, c, ued, ucnt, uhead);
		}
		spfa(1, dis, head, ed);
		if (dis[n] == INF) {
			cout << "0\n";
			continue;
		}
		long long tmp = dis[n];
		spfa(n, udis, uhead, ued);
		for (int i = 0; i < m; i++) {
			int u = ed[i].u, v = ed[i].v;
			if (dis[u] + udis[v] + 1LL * ed[i].w == tmp) {
				addedge(u, v, ed[i].w);
			}
		}
		long long ans = dinic(1, n);
		cout << ans << "\n";
	}
	return 0;
}

// 0 1 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值