kyeremal-网络流24题T3-最小路径覆盖问题
2015-04-21 00:04
381 查看
原题:
大意:在一个有向无环图中,最少要找出几条简单路径,使得每个点都访问过,且每个点只现在一条简单路径中。
分析:一个最小点路径覆盖问题,将每个点i拆成两个点i,i‘,i与i’属于两个不同的集合X,Y,如果i->j有连边,则建立一条从Xi->Yj的流量为1的有向边,显然问题转化为二分图匹配问题,求出最大匹配数,答案=点数-最大匹配树。
输出路径:按照匹配边遍历。
code:
最小路径覆盖问题 问题描述: 给定有向图 G=(V,E)。设 P 是 G 的一个简单路(顶点不相交)的集合。如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 G 的一个路径覆盖。P 中路径可以从 V 的任何一个顶 点开始,长度也是任意的,特别地,可以为 0。G 的最小路径覆盖是 G 的所含路径条数最少 的路径覆盖。 设计一个有效算法求一个有向无环图 G 的最小路径覆盖。 提示:设 V={1,2,o ,n},构造网络 G1=(V1,E1)如下: V1 = {x0 , x1 ,..., xn } ∪ {y0 , y1 ,..., yn }, E 1 = {( x 0 , x i ) : i ∈ V } ∪ {( y i , y 0 ) : i ∈ V } ∪ {( x i , y j ) : ( i . j ) ∈ E } 每条边的容量均为 1。求网络 G1 的( x0 , y0 )最大流。 ́编程任务: 对于给定的给定有向无环图 G,编程找出 G 的一个最小路径覆盖。 ́ 数据输入: 由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 n 和 m。n 是给定有向无环图G 的顶点数,m 是 G 的边数。接下来的 m 行,每行有 2 个正整数 i 和 j,表示一条有向边(i,j)。 ́ 结果输出: 程序运行结束时,将最小路径覆盖输出到文件 output.txt 中。从第 1 行开始,每行输出 一条路径。文件的最后一行是最少路径数。 输入文件示例 input.txt 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 输出文件示例 output.txt 1 4 7 10 11 2 5 8 3 6 9 3
大意:在一个有向无环图中,最少要找出几条简单路径,使得每个点都访问过,且每个点只现在一条简单路径中。
分析:一个最小点路径覆盖问题,将每个点i拆成两个点i,i‘,i与i’属于两个不同的集合X,Y,如果i->j有连边,则建立一条从Xi->Yj的流量为1的有向边,显然问题转化为二分图匹配问题,求出最大匹配数,答案=点数-最大匹配树。
输出路径:按照匹配边遍历。
code:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #include <vector> using namespace std; #define rep(i, l, r) for (int i = l; i <= r; i++) #define REP(i, l, r) for (int i = l; i >= r; i--) #define X first #define Y second #define MAXN 100010 int n, m, N = -1, first[MAXN], next[MAXN], dis[MAXN], S, T, cnt; queue<int> q; struct tlist {int x, y, f;} a[MAXN]; vector<pair<int, int> > v; inline int min(int a, int b) {return a<b ? a : b;} inline void add(int x, int y, int f) { a[++N].x = x, a .y = y, a .f = f, next = first[x], first[x] = N; a[++N].x = y, a .y = x, a .f = 0, next = first[y], first[y] = N; } inline bool bfs() { while (!q.empty()) q.pop(); memset(dis, -1, sizeof(dis)); dis[S] = 0; q.push(S); while (!q.empty()) { int x = q.front(); q.pop(); for (int i = first[x]; ~i; i = next[i]) if ((!~dis[a[i].y]) && a[i].f) { dis[a[i].y] = dis[x] + 1; q.push(a[i].y); } } return ~dis[T]; } inline int find(int x, int low) { int temp; if (x == T) return low; for (int i = first[x]; ~i; i = next[i]) if ((a[i].f)&&(dis[a[i].y] == dis[x] + 1)&&(temp = find(a[i].y, min(low, a[i].f)))) { a[i].f -= temp; a[i^1].f += temp; return temp; } return 0; } inline int dinic(int begin, int end) { S = begin, T = end; int ans = 0, temp; while (bfs()) while (temp = find(S, 0x7fffffff)) ans += temp; return ans; } inline void write() { cnt += v.size(); rep(i, 0, int(v.size())-2) printf("%d ", v[i].X), a[v[i].Y].f = -1; cout << v[int(v.size()) - 1].X << endl; rep(i, 0, int(v.size())-1) a[v[i].Y].f = -1; } inline void dfs(int k) { for (int i = first[k]; ~i; i = next[i]) if (!(i & 1) && !a[i].f) { int t = a[i].y % n; if (!t) t = n; v.push_back(make_pair(t, i)); dfs(t); break; } } int main() { memset(first, -1, sizeof(first)); memset(next, -1, sizeof(next)); cin >> n >> m; rep(i, 1, n) add(0, i, 1), add(n+i, 2*n+1, 1); int tx, ty; rep(i, 1, m) scanf("%d%d", &tx, &ty), add(tx, n+ty, 1); int out = n - dinic(0, 2*n+1); while (cnt < 3*out) { v.clear(); dfs(S); write(); } cout << out << endl; return 0; }
相关文章推荐
- 网络流24题之T3 最小路径覆盖问题
- 网络流24题之T3——最小路径覆盖问题
- 最小路径覆盖问题[网络流24题之3]
- 「网络流24题」最小路径覆盖问题
- ssl 2603 网络流24题3 最小路径覆盖问题
- 网络流24题(03)最小路径覆盖问题(二分图匹配 + 最大流)
- 网络流24题:最小路径覆盖问题
- 线性规划与网络流24题 03最小路径覆盖问题
- 线性规划与网络流24题の4 魔术球问题(最小路径覆盖)
- 网络流与线性规划24题03最小路径覆盖问题
- 网络流24题3 最小路径覆盖问题
- 线性规划与网络流24题之最小路径覆盖问题
- 网络流24题3 最小路径覆盖问题 洛谷 2764
- 网络流24题之四 魔术球问题 最小路径覆盖
- cogs_396_魔术球问题_(最小路径覆盖+二分图匹配,网络流24题#4)
- 网络流24题之最小路径覆盖问题
- 线性规划与网络流24题——03最小路径覆盖问题
- 网络流24题——最小路径覆盖问题
- 线性规划与网络流24题——03最小路径覆盖问题
- 网络流24题(05)魔术球问题(最小路径覆盖 + 最大流)