zoukankan      html  css  js  c++  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 <cstdio>
    #include <cstring>
    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 <class _Tp> 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()
    {
    	do	do	for (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
    ", maxflow, mincost);
    	return 0;
    }
    

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

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

  • 相关阅读:
    00-03.kaliLinux-vi粘贴复制功能配置
    00-02.kaliLinux-配置SSH服务
    00-01.Kali Linux 2020.1修改root用户密码
    Web设计色彩(转载)
    Inno Setup区段之Language篇
    Inno Setup区段之Setup篇
    IE无法获取到input框的值
    Inno Setup之常量篇
    Inno Setup之概念篇
    网络不通排查
  • 原文地址:https://www.cnblogs.com/oier/p/10458540.html
Copyright © 2011-2022 走看看