HDU - 6582 Path
问题是确定断开最短的边使得从1到n最短路长度增加
转化成两个问题:
- 确定边在最短路上
- 确定断开最短路上的那一条边
对于第一个问题,如果边(u,v)在最短路上则dis(1,u) + cost(u,v) + dis(v,n) = dis(1,n)
dis(a,b)代表从a到b的最短距离
其中,dis(1,u)可以直接从1开始跑dij,dis(v,n)可以从n开始反向建图之后dij
对于第二个问题,如果我们用从1到n最短路上的边建图G后,
问题就转化为在该图上求最小花费使得1与n不连通,即最小割
可以反向理解下,如果割掉一条边之后(1,n)仍然在G图上联通那么1到n的最短路长度必然不变,
反之割边后不连通则在原来的图中要么(1,n)不连通,要么最短路增大,因为断开的(u,v)是最短路上的边...
如果wa了注意开ll
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 0x3f3f3f3f3f3f3f;
const int maxn = 2e4 + 7;
int t, n, m, u, v, val;
struct Edg {
int u, v, val;//起点,终点,消耗
};
struct edg {
int v, val;//到达点,消耗
} edges[maxn];
bool operator<(const edg &a, const edg &b) {
return a.val > b.val;
}
vector<Edg> vg;
vector<edg> mp[2][maxn];//0正向,1反向
int dis[2][maxn];
void dij(int st, int op) {
priority_queue<edg> que;
que.push({st, 0});
dis[op][st] = 0;
while (que.size()) {
edg now = que.top();
que.pop();
if (dis[op][now.v] < now.val)
continue;
for (auto to:mp[op][now.v]) {
if (dis[op][to.v] > dis[op][now.v] + to.val) {
dis[op][to.v] = dis[op][now.v] + to.val;
que.push({to.v, dis[op][to.v]});
}
}
}
}
struct Dinic {
struct edge {
int to, cap, rev;
edge(int a, int b, int c) { to = a, cap = b, rev = c; }
};
vector<edge> G[maxn];
int level[maxn];
int iter[maxn];
void init(int n) {
memset(level, 0, sizeof level);
memset(iter, 0, sizeof iter);
for (int i = 0; i <= n; i++)
G[i].clear();
}
void add(int from, int to, int cap) {
G[from].push_back(edge(to, cap, G[to].size()));
G[to].push_back(edge(from, 0, G[from].size() - 1));
}
void bfs(int s) {
memset(level, -1, sizeof level);
queue<int> que;
level[s] = 0;
que.push(s);
while (que.size()) {
int v = que.front();
que.pop();
for (int i = 0; i < G[v].size(); i++) {
edge &e = G[v][i];
if (e.cap > 0 && level[e.to] < 0)
level[e.to] = level[v] + 1, que.push(e.to);
}
}
}
int dfs(int v, int t, int f) {
if (v == t)
return f;
for (int &i = iter[v]; i < G[v].size(); i++) {
edge &e = G[v][i];
if (e.cap > 0 && level[v] < level[e.to]) {
int d = dfs(e.to, t, min(f, e.cap));
if (d > 0) {
e.cap -= d, G[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int run(int s, int t) {
int flow = 0;
while (1) {
bfs(s);
if (level[t] < 0)
return flow;
memset(iter, 0, sizeof iter);
int f;
while ((f = dfs(s, t, mod)) > 0)
flow += f;
}
}
} F;
void init() {
vg.clear(), F.init(n + 1);
for (int i = 0; i <= n; ++i)
dis[0][i] = dis[1][i] = mod,
mp[0][i].clear(), mp[1][i].clear();
}
signed main() {
cin >> t;
while (t--) {
cin >> n >> m;
init();
for (int i = 1; i <= m; i++) {
cin >> u >> v >> val;
vg.push_back({u, v, val});
mp[0][u].push_back({v, val});
mp[1][v].push_back({u, val});
}
dij(1, 0);
dij(n, 1);
for (auto eg:vg)
if (dis[0][eg.u] + eg.val + dis[1][eg.v] == dis[0][n])
F.add(eg.u, eg.v, eg.val);
cout << F.run(1, n) << endl;
}
}
我看见 你