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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章