Marriage Match IV HDU - 3416
题目大意:让你找出有多少条没有交集的最短路。
思路:先用spfa找出可行的边,然后给每条可行的边加上容量1.即表示这条边只能走一次。
接下来跑一遍ISAP就可以得出答案。
关于判断边可行的方法如下。
先从头跑一遍spfa,得到起点到其他所有点的最短路径dis1
再从尾跑一遍spfa,得到终点到其他所有点的最短路径dis2
对于边u-v w
假如dis1[u]+dis2[v]+w==dis1[终点]这可以得出结论,u-v这条边在一条最短路上。然后给这条边加上容量一。
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e3 + 5, M = 2e5 + 5, INF = 2e9;
struct E {
int v, w, next;
} e[M], we[M]; //we保存网络流的图
int cas, n, m, s, t, u[M], v[M], w[M], len, wlen, h[N], rh[N], wh[N], d[N], rd[N], de[N];
bool vis[N];
//求2次最短路
void add(int h[], int u, int v, int w) {
e[++len].v = v;e[len].w = w;e[len].next = h[u];h[u] = len;
}
void wadd(int h[], int u, int v, int w) {
we[++wlen].v = v;we[wlen].w = w;we[wlen].next = h[u];h[u] = wlen;
}
void spfa(int h[], int d[], int s) {
memset(d, 0x3f, (n + 1) * sizeof(int));
d[s] = 0;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for (int j = h[u]; j; j = e[j].next) {
int v = e[j].v;
int w = e[j].w + d[u];
if (d[v] > w) {
d[v] = w;
if (!vis[v]) q.push(v), vis[v] = true;
}
}
}
}
bool bfs() { //通过残量网络构建出分层图
memset(de, 0, (n + 1) * sizeof(int));
de[s] = 1;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int j = wh[u]; j; j = we[j].next) {
int v = we[j].v;
if (we[j].w && !de[v]) {
de[v] = de[u] + 1;
q.push(v);
if (v == t) return 1;
}
}
}
return 0;
}
int dinic(int u, int flow) {
if (u == t) return flow;
int rest = flow, k;
for (int j = wh[u]; j && rest; j = we[j].next) {
int v = we[j].v;
if (we[j].w && de[v] == de[u] + 1) {
k = dinic(v, min(rest, we[j].w));
if (!k) de[v] = 0;
we[j].w -= k;
we[j ^ 1].w += k;
rest -= k;
}
}
return flow - rest;
}
int main() {
scanf("%d", &cas);
while (cas--) {
memset(h, 0, sizeof(h)); len = 0;
memset(rh, 0, sizeof(rh));
memset(wh, 0, sizeof(wh));wlen = 1;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u[i], &v[i], &w[i]);
if (u[i] == v[i]) continue;
add(h, u[i], v[i], w[i]);
add(rh, v[i], u[i], w[i]); //反向边
}
scanf("%d%d", &s, &t);
spfa(h, d, s); //2次最短路
spfa(rh, rd, t);
//构建网络图 保存最短路的边 并设置流量为1
for (int i = 1; i <= m; i++) {
int a = u[i], b = v[i], c = w[i];
if (a != b && d[a] + c + rd[b] == d[t]) {
wadd(wh, a, b, 1); wadd(wh, b, a, 0);
}
}
//求s-->t的最大流
int ans = 0, flow;
while (bfs()) {
while (flow = dinic(s, INF)) ans += flow;
}
printf("%d\n", ans);
}
return 0;
}