题目大意:
一张图里有n个节点,m条边,要让我们去割掉一些边,让从1到n的距离增大。
解题思路:
首先跑一遍从1 - n 的最短路,然后得到d1数组,然后根据性质:d[v] == d[u] + w[i], 这个性质得到最短路的边,然后重新构建一个最短路径的图,然后再求这张新图的最小割。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, m, s, t;
int h[maxn], e[maxn * 2], ne[maxn * 2], idx;
int d[maxn];
LL d1[maxn], w[maxn * 2];
LL ans, maxflow;
bool vis[maxn];
//构图
int ncu_x[maxn], ncu_y[maxn];
LL ncu_w[maxn];
int permt;
int h1[maxn], e1[maxn * 2], ne1[maxn * 2], idx1;
LL w1[maxn * 2];
inline void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
inline void add1(int a, int b, LL c) {
e1[idx1] = b, w1[idx1] = c, ne1[idx1] = h1[a], h1[a] = idx1 ++;
e1[idx1] = a, w1[idx1] = 0, ne1[idx1] = h1[b], h1[b] = idx1 ++;
}
inline void dijkstra(void) {
memset(vis, false, sizeof vis);
memset(d1, 0x3f, sizeof d1);
priority_queue<PII, vector<PII>, greater<PII> > q;
d1[1] = 0;
q.push({0, 1});
while(q.size()) {
PII tmp = q.top(); q.pop();
int u = tmp.second, du = tmp.first;
vis[u] = true;
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(vis[v]) continue;
if(d1[v] > d1[u] + w[i]) {
d1[v] = d1[u] + w[i];
q.push({d1[v], v});
}
}
}
}
inline bool bfs(void) {
queue<int> q;
while(q.size()) q.pop();
memset(d, 0, sizeof d);
q.push(s), d[s] = 1;
while(q.size()) {
int u = q.front(); q.pop();
for(int i = h1[u]; i != -1; i = ne1[i]) {
int v = e1[i];
if(w1[i] && !d[v]) {
q.push(v);
d[v] = d[u] + 1;
}
}
}
if(d[t] == 0) return false;
return true;
}
inline LL dinic(int u, LL flow) {
if(u == t) return flow;
for(int i = h1[u]; i != -1; i = ne1[i]) {
int v = e1[i];
if(d[v] == d[u] + 1 && w1[i]) {
int k = dinic(v, min(flow, w1[i]));
if(k) {
w1[i] -= k;
w1[i ^ 1] += k;
return k;
} else d[v] = 0;
}
}
return 0;
}
int main(void) {
freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
idx = 0;
for(int i = 1; i <= m; i ++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, (LL)c);
}
//找最短路
dijkstra();
if(d1[n] == inf) printf("0\n");
else {
//重新构图
memset(h1, -1, sizeof h1), idx1 = 0;
for(int u = 1; u <= n; u ++)
for(int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if(d1[v] == d1[u] + w[i])
add1(u, v, w[i]);
}
//找到最小割
s = 1, t = n;
LL flow;
maxflow = 0;
while(bfs())
while(flow = dinic(1, inf)) maxflow += flow;
printf("%lld\n", maxflow);
}
}
fclose(stdin);
return 0;
}
注意点:
1.注意数组的大小不要开小了
2.当我们重新构图的时候可以重新开辟新的数组空间进行重新构图,没有必要去重新初始化原图(我最开始是重新初始化原图,怎么改也改不对)
3. == 不要写成了 = !!!(坑了我几个小时,在这个地方)
4. == 不要写成了 = !!!(坑了我几个小时,在这个地方)
5. == 不要写成了 = !!!(坑了我几个小时,在这个地方)