#HDU 6582 Path (最小割 + 最短路)

17 篇文章 0 订阅
14 篇文章 0 订阅

Path

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3759    Accepted Submission(s): 1077


 

Problem Description

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 n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n.
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), the number of test cases.
Each test case starts with a line containing two numbers n,m(1≤n,m≤10000), the number of houses and the number of one-way roads in the neighbourhood.
m lines follow, each of which consists of three integers x,y,c(1≤x,yn,1≤c≤109), denoting that there exists a one-way road from the house indexed x to y of length c.

 

 

Output

Print T 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

 题目大意 : 有N个点, M条单向赋权边, 你可以堵塞一些道路, 输出你最小花费使从1 到 N的最短路变大(也可以无法到达)

思路 : 由于要处理最短路上的边, 不妨先跑一遍最短路, 把路径全部记录下来, 然后把所有可能成为最短路的路径存到一张新图当中, 跑一遍最小割就解决了, 不明白的话多画几张图, 当时以为是双向边疯狂WA

Accepted code

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

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

struct Edge
{
	int v, next;
	ll w;
}e[MAXN << 1], edge[MAXN]; // e代表原图, edge代表新图
struct node
{
	int id; ll w;
	bool operator < (const node &oth) const
	{
		return w > oth.w;
	}
}mid;
struct point
{
	int u, v; ll w;  // 方便找可能的最短路径
}p[MAXN];
int head[MAXN], fa[MAXN], n, m, cnt, tot, T;  // head为原图边, fa为新图边
int pre[MAXN], dep[MAXN], cur[MAXN], sp, tp;  // pre存最短路
ll dis[MAXN];
bool vis[MAXN];
void init() {
	MEM(head, -1); MEM(pre, -1);
	MEM(fa, -1); MEM(e, 0); MEM(edge, 0);
	cnt = tot = 0;
}
void add(int from, int to, ll wi) {
	e[++cnt].v = to;
	e[cnt].w = wi;
	e[cnt].next = head[from];
	head[from] = cnt;
}
void Add(int from, int to, ll wi) {
	edge[tot].v = to; edge[tot].w = wi;
	edge[tot].next = fa[from]; fa[from] = tot++;

	edge[tot].v = from; edge[tot].w = 0;
	edge[tot].next = fa[to]; fa[to] = tot++;
}
void dijkstra(int u) {
	priority_queue <node> q;
	MEM(dis, INF); dis[u] = 0;
	q.push({ u, 0 }); MEM(vis, 0);
	while (!q.empty()) {
		mid = q.top();
		q.pop();
		int ans = mid.id;
		if (vis[ans] || dis[ans] != mid.w) continue;
		vis[ans] = 1;
		for (int i = head[ans]; i != -1; i = e[i].next) {
			int vi = e[i].v;
			if (dis[vi] > dis[ans] + e[i].w) {
				dis[vi] = dis[ans] + e[i].w;
				q.push({ vi, dis[vi] });
				pre[vi] = ans;
			}
		}
	}
}
bool bfs() {
	queue <int> q;
	MEM(dep, 0); q.push(sp);
	dep[sp] = 1;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		for (int i = fa[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;
	else return false;
}
ll dfs(int x, ll wi) {
	if (x == tp || wi == 0) return wi;
	ll 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, wi - res));
			if (r > 0) {
				edge[i].w -= r;
				edge[i ^ 1].w += r;
				res += r;
				if (res == wi) return wi;
			}
		}
	}
	if (!res) dep[x] = 0;
	return res;
}
ll dinic() {
	ll flow = 0;
	while (bfs()) {
		for (int i = 1; i <= n; i++) cur[i] = fa[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; ll wi;
			sc("%d %d %lld", &ui, &vi, &wi);
			add(ui, vi, wi);
			p[i].u = ui, p[i].v = vi, p[i].w = wi;
		}
		dijkstra(1);
		for (int i = 0; i < m; i++) {
			int ui = p[i].u, vi = p[i].v; ll wi = p[i].w;
			if (dis[vi] - dis[ui] == wi)  // 是最短路上的边
				Add(ui, vi, wi);
		}
		sp = 1, tp = n;
		ll ans = dinic();
		cout << ans << endl;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值