先让我们回顾一下SPFA算法:
设d[x] = x到T的最短距离
对于i,j必有d[j] + c[i][j] >= d[i]
SPFA算法就是每次找到d[j] + c[i][j] = d[i]的等式,走最短路更新答案。
这样的话没有充分利用到已经求过的,有些图会很慢。
我们可以借鉴KM算法的思想,每次把d[i]增大一点点,就可以找到范围更大的j,答案也是对的。每次增高的距离就是已走过点到为走过点的最小高度差,类似于sap。
基础:
int n, S, T, ans1, ans2; // ans1表示最大流量, ans2表示最小费用。
int tot = 1, final[Maxn], dis[Maxn], bz[Maxn]; // dis表示到T的距离。
struct edge {
int to, next, r, w;
}a[Maxm];
void link(int x,int y,int r,int w) {
a[++tot].next = final[x], a[tot].to = y, a[tot].r = r, a[tot].w = w, final[x] = tot;
a[++tot].next = final[y], a[tot].to = x, a[tot].r = 0, a[tot].w = -w, final[y] = tot;
} //前向星加边
ZKW:
int aug(int x,int flow) {
if(x == T) {
ans1 += flow;
ans2 += dis[S] * flow;
return flow;
}
bz[x] = 1;
int use = 0;
for(int i = final[x]; i; i = a[i].next) {
int y = a[i].to;
if(!bz[y] && a[i].r && dis[y] + a[i].w == dis[x]) {
int tmp = aug(y, min(a[i].r, flow - use));
a[i].r -= tmp; a[i ^ 1].r += tmp; use += tmp;
if(use == flow) return use;
}
}
return use;
}
bool change() {
int minh = INF;
fo(i, 1, T) if(bz[i])
for(int k = final[i]; k; k = a[k].next)
if(a[k].r && !bz[a[k].to])
minh=min(minh, dis[a[k].to] + a[k].w - dis[i]);
if(minh == INF) return 0;
fo(i, 1, T) if(bz[i])
dis[i] += minh;
return 1;
}