费用流模板——ZKW

先让我们回顾一下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;
}

你可能感兴趣的:(模版,费用流)