滑蒻稽的博客

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

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 了两个点。

posted @ 2022-04-12 19:10  huaruoji  阅读(629)  评论(1编辑  收藏  举报