费用流模板——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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值