题目描述
«问题描述:
给定有向图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<=n<=150,1<=m<=6000
由@zhouyonglong提供SPJ
搬得洛谷的......
AC 代码
// 未完待续...... // 二分图的最小覆盖等于节点数 - 最大匹配 #include <cstdio> #include <algorithm> #include <queue> #include <cstring> using namespace std; const int N = 2e5 + 10; const int inf = 0x3f3f3f3f; int n, m; struct Max_flow { int head[N], v[N], to[N], pos[N], cur[N], dep[N], st[N], p, s, t; void build(int a, int b, int c) { v[++ p] = b; to[p] = head[a]; head[a] = p; pos[p] = c; st[p] = a; } void clear() { memset(head, -1, sizeof(head)); p = -1; } queue < int > tc; bool bfs() { memset(dep, 0, sizeof(dep)); for ( int i = 0; i <= p; i ++) cur[i] = head[i]; while( !tc.empty()) tc.pop(); tc.push(s); dep[s] = 1; while( !tc.empty()) { int u = tc.front(); tc.pop(); for ( int i = head[u]; ~i; i = to[i]) if( pos[i] > 0 && !dep[v[i]]) dep[v[i]] = dep[u] + 1, tc.push(v[i]); if( dep[t]) return true; } return false; } int son[N], pre[N]; int dfs(int u, int tot) { if( u == t || !tot) return tot; int flow = 0; for ( int i = cur[u]; ~i; i = to[i]) { cur[u] = i; if( dep[u] + 1 == dep[v[i]]) { int k = dfs(v[i], min(tot, pos[i])); if( k) { pre[v[i]] = u; son[u] = v[i]; pos[i] -= k; pos[i^1] += k; tot -= k; flow += k; if( !tot) return flow; } } } return flow; } void out(int x) { printf("%d ", x); for ( int i = head[x]; ~i; i = to[i]) if( v[i] > n && pos[i] == 0) out(v[i] - n); } int find(int x) { return pre[x] == x ? x : pre[x] = find(pre[x]); } int max_flow() { int ans = 0; while( bfs()) ans += dfs(s, inf); for ( int i = 1; i <= n; i ++) pre[i] = i; for ( int i = 0; i <= p; i ++) if( st[i] > s && st[i] <= n && v[i] > n && v[i] < t && pos[i] == 0) { pre[find(v[i] - n)] = find(st[i]); } for ( int i = 1; i <= n; i ++) if(pre[i] == i) out(i), puts(""); return ans; } }g; int main() { g.clear(); scanf("%d%d", &n, &m); g.s = 0; g.t = n << 1|1; for ( int i = 1; i <= n; i ++) g.build(g.s, i, 1), g.build(i, g.s, 0), g.build(i+n, g.t, 1), g.build(g.t, i+n, 0); for ( int i = 1, a, b; i <= m; i ++) scanf("%d%d", &a, &b), g.build(a, b+n, 1), g.build(b+n, a, 0); printf("%d\n", n - g.max_flow()); }
题解之后补