1. 程式人生 > >P2764 最小路徑覆蓋問題

P2764 最小路徑覆蓋問題

mem oid space edge int 二分 格式 set fin

題目描述

?問題描述:

給定有向圖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 #include<cstdio>
  2
#include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 #define inf 0x3fffffff 7 using namespace std; 8 const int maxn = 1e5 + 10; 9 int head[maxn], sign, cur[maxn]; 10 int s, t, d[maxn]; 11 struct node { 12 int to, w, next; 13 } edge[maxn] ;
14 void creat() { 15 memset(head, -1, sizeof(head)); 16 sign = 0; 17 } 18 void add(int u, int v, int w) { 19 edge[sign].to = v; 20 edge[sign].w = w; 21 edge[sign].next = head[u]; 22 head[u] = sign++; 23 edge[sign].to = u; 24 edge[sign].w = 0; 25 edge[sign].next = head[v]; 26 head[v] = sign++; 27 } 28 int bfs() { 29 queue<int>q; 30 memset(d, 0, sizeof(d)); 31 d[s] = 1; 32 q.push(s); 33 while(!q.empty()) { 34 int top = q.front(); 35 q.pop(); 36 for (int i = head[top] ; ~i ; i = edge[i].next ) { 37 int to = edge[i].to; 38 if (edge[i].w > 0 && d[to] == 0) { 39 d[to] = d[top] + 1; 40 if (to == t) return 1; 41 q.push(to); 42 } 43 } 44 } 45 return d[t] != 0; 46 } 47 int dfs(int top, int flow ) { 48 if (top == t) return flow; 49 int ans = 0, x = 0; 50 for (int i = cur[top] ; ~i ; i = edge[i].next) { 51 int to = edge[i].to; 52 if (edge[i].w > 0 && d[to] == d[top] + 1) { 53 x = dfs(to, min(flow - ans, edge[i].w)) ; 54 edge[i].w -= x; 55 edge[i ^ 1].w += x; 56 if (edge[i].w) cur[top] = i; 57 ans += x; 58 if (ans == flow) return flow; 59 } 60 } 61 if (ans == 0) return d[top] = 0; 62 return ans; 63 } 64 65 int dinic(int n) { 66 int ans = 0; 67 while(bfs()) { 68 for (int i = 0 ; i <= n ; i++) 69 cur[i] = head[i]; 70 ans += dfs(s, inf); 71 } 72 return ans; 73 } 74 int n, m, vis[maxn]; 75 void go(int x, int &f) { 76 int loc = x + n; 77 vis[x] = 1; 78 for (int i = head[loc] ; ~i ; i = edge[i].next) 79 if (edge[i].w == 1 && edge[i].to != n * 2 + 1) go(edge[i].to, f) ; 80 if (f == 1) f = 0; 81 printf(" "); 82 printf("%d", x); 83 } 84 int main() { 85 scanf("%d%d", &n, &m); 86 creat(); 87 s = 0, t = 2 * n + 1; 88 for (int i = 1 ; i <= n ; i++) 89 add(s, i, 1), add(i + n, t, 1); 90 int x, y; 91 while(m--) { 92 scanf("%d%d", &x, &y); 93 add(x, y + n, 1); 94 } 95 int ans = n - dinic(t); 96 for (int i = head[t]; ~i ; i = edge[i].next) { 97 if (edge[i].w == 1 && !vis[edge[i].to - n]) { 98 int f = 1; 99 go(edge[i].to - n, f); 100 printf("\n"); 101 } 102 } 103 printf("%d\n", ans); 104 return 0; 105 }



P2764 最小路徑覆蓋問題