zkw费用流 java_zkw费用流

zkw费用流学习笔记

根据OI业界潜规则,出网络流题目时候,最大流不能卡 dinic ,费用流不能卡 ek ,但是我今天做了一道 [SDOI2009]最优图像 把我惊到了,反正就是把费用流的 ek 算法给卡了,所以今天还要学习一下这个 zkw费用流

说到 zkw费用流,我就想起今年上半年NOIWC2019上laofu讲到的模拟费用流问题

算法流程:每次先dfs一遍(和dinic的dfs一样)dfs增广,用一个vis数组记录下增广过程中经过了哪些点,然后再xjb维护一下每个点的顶标,下面代码观察的angle_kitty巨佬的,维护顶标的做法是直接把顶标扔费用里了(可能比较好些但是不是很好理解反正我没理解背过就行

维护顶标就是找所有增广过点连出的流量中花费最小的一个,让正向边花费减去它反向边花费加上它,还要维护一个全全局变量(可能是代表从src到dest默认已经付的路费吧

代码不长,和dinic差不多,性能比EK好

另外在最优图像那道题中由于没有SPJ,这么写会WA,期望你谷早日配上SPJ(我只会写lemon风格的SPJ,testlib的不会写) BZ和loj都没那道题。。

一下为你谷费用流模板代码

#include

#include

using namespace std;

struct edge { int v, ne, flow; int cost; } a[1000010];

int h[12306], n, m, tmp = 1, src = 1, dest = 2, tot = 2, maxflow;

int dis[12306], now[12306], mincost, co;

bool vis[12306];

template void chkmin(_Tp &a, _Tp b) { if (a > b) a = b; }

void add(int x, int y, int flow, int cost) { a[++tmp] = (edge){y, h[x], flow, cost}; h[x] = tmp; }

void add1(int x, int y, int flow, int cost) { add(x, y, flow, cost), add(y, x, 0, -cost); }

int aug(int x, int want)

{

if (x == dest) { mincost += co * want, maxflow += want; return want; }

vis[x] = true;

int get = 0;

for (int i = now[x]; i != 0; i = a[i].ne)

{

if (a[i].flow > 0 && a[i].cost == 0 && vis[a[i].v] == false)

{

int f = aug(a[i].v, min(a[i].flow, want));

a[i].flow -= f, a[i ^ 1].flow += f;

want -= f, get += f;

}

now[x] = i;

if (want == 0) break;

}

return get;

}

bool modlabel()

{

int tmp = 1e9;

for (int x = 1; x <= tot; x++) if (vis[x])

for (int i = h[x]; i != 0; i = a[i].ne)

if (a[i].flow > 0 && vis[a[i].v] == false)

chkmin(tmp, a[i].cost);

if (tmp == 1e9) return false;

for (int x = 1; x <= tot; x++) if (vis[x])

for (int i = h[x]; i != 0; i = a[i].ne)

a[i].cost -= tmp, a[i ^ 1].cost += tmp;

co += tmp;

return true;

}

void zkw()

{

dodofor (int i = 1; i <= tot; i++) now[i] = h[i], vis[i] = false;

while (aug(src, 1e9));

while (modlabel());

}

int main()

{

scanf("%d%d%d%d", &tot, &m, &src, &dest);

for (int x, y, w, f, i = 1; i <= m; i++)

scanf("%d%d%d%d", &x, &y, &w, &f), add1(x, y, w, f);

zkw();

printf("%d %d\n", maxflow, mincost);

return 0;

}

最优图像那题把这个代码xjb改改就可以A掉了,由于那题是对概率取log所以要开double(逗拨),所以可能涉及写精度问题(貌似不用判精度...不过我对实数过敏)反正那道题上zkw绝对不会卡常啦

备注:很多博客(例如olinr的博客)里的zkw费用流是假的,那是多路增广dinic,zkw费用流是要维护一些东西的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值