题目链接:https://www.luogu.org/problemnew/show/P2764
«问题描述:
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:
每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。
«编程任务:
对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。
输入输出格式
输入格式:
件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
输出格式:
从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。
输入输出样例
输入样例#1: 复制
11 12 1 2 1 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 11 10 11输出样例#1: 复制
1 4 7 10 11 2 5 8 3 6 9 3说明
1<=n<=150,1<=m<=6000
对于一个路径覆盖,有如下概念:
①:每个顶点只属于一个路径;
②:路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
将所有点拆成功入点和出点,源点连所有入点,汇点连所有出点,所有边容量都为1,而对于每个边u-v来说,只连
u的入点和v的出点,这样保证了每个点至少会走一次。最后还原路径,对于每个起点,每次走与他相连且残留量为0
的点并标记。
最小路径覆盖数=顶点数-二分最大匹配数
#pragma GCC optimize(2) #include<stdio.h> #include<algorithm> #include<string.h> #include<queue> using namespace std; const int maxn = 1e5; const int inf = 0x3f3f3f3f; typedef long long ll; int head[maxn], level[maxn]; int n, m, tot; struct node { int v, w, next; }edge[maxn]; void addedge(int u, int v, int w) { edge[tot].v = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot++; edge[tot].v = u; edge[tot].w = 0; edge[tot].next = head[v]; head[v] = tot++; return; } bool bfs(int s, int t) { queue<int>q; memset(level, 0, sizeof(level)); level[s] = 1; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if (level[v] == 0 && edge[i].w) { level[v] = level[u] + 1; q.push(v); } } } return level[t] != 0; } int dfs(int s, int t, int f) { if (s == t) { return f; } int cost = 0; for (int i = head[s]; i != -1; i = edge[i].next) { int v = edge[i].v; if (level[v] == level[s] + 1 && edge[i].w > 0) { int d = dfs(v, t, min((f - cost), edge[i].w)); if (d > 0) { edge[i].w -= d; edge[i ^ 1].w += d; cost += d; if (cost == f) { break; } } else { level[v] = -1; } } } return cost; } int dinic(int s, int t) { int flow = 0; while (bfs(s, t)) { flow += dfs(s, t, inf); } return flow; } int main() { //freopen("C://input.txt", "r", stdin); while (scanf("%d%d", &n, &m) != EOF) { int s =0, t = 2 * n + 1; tot = 0; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); addedge(u, v + n, 1); } for (int i = 1; i <= n; i++) { addedge(s, i, 1); addedge(i + n, t, 1); } int sum = n - dinic(s, t); int vis[maxn]; memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) { if (vis[i]) { continue; } int flag = 0, now = i; while (1) { flag = 0; printf("%d ", now); vis[now] = 1; for (int j = head[now]; j != -1; j = edge[j].next) { int v = edge[j].v; if (edge[j].w == 0 && v > n&&v < t) { now = v - n; flag = 1; break; } } if (!flag) { break; } } printf("\n"); } printf("%d\n", sum); } return 0; }
网络流24题 最小路径覆盖问题(最小割模型)
最新推荐文章于 2021-07-08 16:29:53 发布