• 【笔记】正确的当前弧优化


    UOJ 上测了一下某“当前弧优化”的写法,虽然那题是准备给 ISAP 的模板,但是 \(O(n^2m)\) 肯定能过的点也没有跑过。这就令人好奇了。。

    当前弧优化应当这么写(原因在注释里):

    ll dfs(int u, ll flow) {
    	if (u == T) return flow;
    	ll rest = flow;
    	for (int &i = nhd[u]; i; i = e[i].nxt) {
    		int v = e[i].v;
    		if (e[i].f && d[v] == d[u] + 1) {
    			ll k = dfs(v, min(rest, (ll)e[i].f));
    			if (!k) d[v] = 0;
    			rest -= k, e[i].f -= k, e[i ^ 1].f += k;
    		}
    		// rest 为 0 不代表不能继续走这条边扩展增广路,因为 rest 实际上是上一个点跑过来的流量。后面可能从另一条路径到达这条边,并且能通过这条边扩展,所以不能把 nhd[u] 设置为这条边的 nxt 导致以后都跳过这条边。
    		if (!rest) break;
    	}
    	return flow - rest;
    }
    

    而不是蓝书上写的:

    ll dfs(int u, ll flow) {
    	if (u == T) return flow;
    	ll rest = flow;
    	for (int &i = nhd[u]; i && rest; i = e[i].nxt) {
    		int v = e[i].v;
    		if (e[i].f && d[v] == d[u] + 1) {
    			ll k = dfs(v, min(rest, (ll)e[i].f));
    			if (!k) d[v] = 0;
    			rest -= k, e[i].f -= k, e[i ^ 1].f += k;
    		}
    	}
    	return flow - rest;
    }
    

    其实就是,仅当从某条边出发无法增广的时候才能把该边抛弃掉。如果因为 rest 不够而不能增广,不能说明该边无法增广。

    顺便给一个单路增广的写法,从这个写法扩展完全能得到正确的多路增广:

    int dfs(int u, int flow) {
      if (u == T) return flow;
      for (int &i = nhd[u]; i; i = e[i].nxt) {
        int v = e[i].v;
        if (e[i].f && d[v] == d[u] + 1) {
          int k = dfs(v, min(flow, e[i].f));
          if (!k) continue;
          e[i].f -= k, e[i ^ 1].f += k;
          return k;
        }
      }
      return 0;
    }
    

    并且单路增广和多路增广在洛谷上用时几乎没有差别,在 UOJ 上单路比多路多 T 了两个点。

  • 相关阅读:
    杨晓峰-Java核心技术-6 动态代理 反射 MD
    ARouter 路由 组件 跳转 MD
    领扣-5 最长回文子串 Longest Palindromic Substring MD
    算法 递归 迭代 动态规划 斐波那契数列 MD
    二叉树 遍历 先序 中序 后序 深度 广度 MD
    算法 数组中出现次数最多的数字 MD
    领扣-754 到达终点数字 Reach a Number MD
    领扣-1/167 两数之和 Two Sum MD
    文件 File 常见操作 工具 MD
    IO流 简介 总结 API 案例 MD
  • 原文地址:https://www.cnblogs.com/huaruoji/p/16136531.html
Copyright © 2020-2023  润新知