題目大意:
一張圖裏有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. == 不要寫成了 = !!!(坑了我幾個小時,在這個地方)