Luogu P2764 最小路径覆盖问题

题目链接:传送门

最小路径覆盖问题
最小路径覆盖就是用最少的路径条数,不重复不遗漏地覆盖一个有向无环图的所有顶点。
解法:

  • 首先将原图中的每个点拆为xxx+nx+n,原图中的点在左侧,拆出来的大于nn的点在右侧,这样就形成了一个二分图。
  • 对于原图中的边(x,y)(x,y),在新建立的二分图中连边(x,y+n)(x,y+n),容量为11,这样建出来的图叫拆点二分图。

然后,最小路径覆盖 = 原图点数 – 拆点二分图的最大匹配
对这个定理的简单理解:将原图拆成二分图之后,每个点都是独立的一个路径,长度为00,每连一条边就会减少一条路径,连边的过程就是匹配的过程,所以要使路径最少,匹配就要最大。
这个最大匹配用匈牙利和网络流都可
但是题目要求输出路径,DinicDinic中标记路径中的起点再记录一下后继即可

#include <bits/stdc++.h>
#define A 1000010

using namespace std;
struct node {int nt, to, w;}e[A];
int hd[A], num = -1;
void add(int fr, int to, int w) {e[++num].nt = hd[fr]; e[num].to = to; e[num].w = w; hd[fr] = num;}
int n, m, dep[A], nxt[A], S, T, a, b, cur[A]; bool vis[A], inq[A];
bool bfs() {
	memset(dep, 0x3f, sizeof dep); memset(vis, 0, sizeof vis);
	queue<int> q; q.push(S); dep[S] = 0; vis[S] = 1;
	while (!q.empty()) {
		int fr = q.front(); q.pop(); vis[fr] = 0;
		for (int i = hd[fr]; ~i; i = e[i].nt) {
			int ca = e[i].to;
			if (dep[ca] > dep[fr] + 1 and e[i].w) {
				dep[ca] = dep[fr] + 1;
				if (!vis[ca]) vis[ca] = 1, q.push(ca);
			}
		}
	}
	return dep[T] != 0x3f3f3f3f;
}
int dfs(int fr, int flow, int now = 0) {
	if (fr == T) return flow;
	for (int &i = cur[fr]; ~i; i = e[i].nt) {
		int ca = e[i].to;
		if (dep[ca] == dep[fr] + 1 and e[i].w) {
			now = dfs(ca, min(flow, e[i].w));
			if (now) {
				nxt[fr] = ca - n; inq[ca - n] = 1;
				e[i].w -= now; e[i ^ 1].w += now;
				return now;
			}
		}
	}
	return 0;
}
int dinic(int ans = 0) {
	while (bfs()) {
		memcpy(cur, hd, sizeof hd);
		while (int t = dfs(S, 0x3f3f3f3f)) ans += t;
	}
	return ans;
}

int main(int argc, char *argv[]) {
	memset(hd, -1, sizeof hd);
	scanf("%d%d", &n, &m); S = 0; T = n << 1 | 1;
	for (int i = 1; i <= m; i++) scanf("%d%d", &a, &b), add(a, b + n, 1), add(b + n, a, 0);
	for (int i = 1; i <= n; i++) add(S, i, 1), add(i, S, 0), add(i + n, T, 1), add(T, i + n, 0);
	int xxw = n - dinic();
	for (int i = 1; i <= n; i++)
		if (!inq[i]) {
			for (int j = i; j; j = nxt[j]) printf("%d ", j);
			puts("");
		}
	printf("%d\n", xxw);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章