1. 程式人生 > >[cogs729]圓桌問題(最大流)

[cogs729]圓桌問題(最大流)

for isp front 集合 targe 一個人 getchar 分析 freopen

傳送門

模型

二分圖多重匹配問題,可以用最大流解決。

實現

建立二分圖,每個單位為X集合中的頂點,每個餐桌為Y集合中的頂點,增設附加源S和匯T。

1、從S向每個Xi頂點連接一條容量為該單位人數的有向邊。

2、從每個Yi頂點向T連接一條容量為該餐桌容量的有向邊。

3、X集合中每個頂點向Y集合中每個頂點連接一條容量為1的有向邊。

求網絡最大流,如果最大流量等於所有單位人數之和,則存在解,否則無解。對於每個單位,從X集合對應點出發的所有滿流邊指向的Y集合的頂點就是該單位人員的安排情況(一個可行解)。

分析

對於一個二分圖,每個頂點可以有多個匹配頂點,稱這類問題為二分圖多重匹配問題。X,Y集合之間的邊容量全部是1,保證兩個點只能匹配一次(一個餐桌上只能有一個單位的一個人),源

匯的連邊限制了每個點匹配的個數。求出網絡最大流,如果流量等於X集合所有點與S邊容量之和,那麽則說明X集合每個點都有完備的多重匹配。

註意 cogs 需要寫文件!

——代碼

技術分享
  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #define N 50001
  6 #define M 5000001
  7 #define min(x, y) ((x) < (y) ? (x) : (y))
  8
9 int n, m, cnt, sum, ans, s, t; 10 int head[N], to[M], val[M], next[M], dis[N], cur[N]; 11 12 inline int read() 13 { 14 int x = 0, f = 1; 15 char ch = getchar(); 16 for(; !isdigit(ch); ch = getchar()) if(ch == -) f = -1; 17 for(; isdigit(ch); ch = getchar()) x = (x << 1
) + (x << 3) + ch - 0; 18 return x * f; 19 } 20 21 inline void add(int x, int y, int z) 22 { 23 to[cnt] = y; 24 val[cnt] = z; 25 next[cnt] = head[x]; 26 head[x] = cnt++; 27 } 28 29 inline bool bfs() 30 { 31 int i, u, v; 32 std::queue <int> q; 33 memset(dis, -1, sizeof(dis)); 34 q.push(s); 35 dis[s] = 0; 36 while(!q.empty()) 37 { 38 u = q.front(), q.pop(); 39 for(i = head[u]; i ^ -1; i = next[i]) 40 { 41 v = to[i]; 42 if(val[i] && dis[v] == -1) 43 { 44 dis[v] = dis[u] + 1; 45 if(v == t) return 1; 46 q.push(v); 47 } 48 } 49 } 50 return 0; 51 } 52 53 inline int dfs(int u, int maxflow) 54 { 55 if(u == t) return maxflow; 56 int v, d, ret = 0; 57 for(int &i = cur[u]; i ^ -1; i = next[i]) 58 { 59 v = to[i]; 60 if(val[i] && dis[v] == dis[u] + 1) 61 { 62 d = dfs(v, min(val[i], maxflow - ret)); 63 ret += d; 64 val[i] -= d; 65 val[i ^ 1] += d; 66 if(ret == maxflow) return ret; 67 } 68 } 69 return ret; 70 } 71 72 int main() 73 { 74 freopen("roundtable.in","r",stdin); 75 freopen("roundtable.out","w",stdout); 76 int i, j, x; 77 m = read(); 78 n = read(); 79 s = 0, t = n + m + 1; 80 memset(head, -1, sizeof(head)); 81 for(i = 1; i <= m; i++) 82 { 83 sum += x = read(); 84 add(s, i, x), add(i, s, 0); 85 for(j = 1; j <= n; j++) 86 add(i, j + m, 1), add(j + m, i, 0); 87 } 88 for(i = 1; i <= n; i++) 89 { 90 x = read(); 91 add(i + m, t, x), add(t, i + m, 0); 92 } 93 while(bfs()) 94 { 95 for(i = s; i <= t; i++) cur[i] = head[i]; 96 ans += dfs(s, 1e9); 97 } 98 if(ans ^ sum) 99 { 100 puts("0"); 101 return 0; 102 } 103 puts("1"); 104 for(i = 1; i <= m; puts(""), i++) 105 for(j = head[i]; j ^ -1; j = next[j]) 106 if(!val[j]) 107 printf("%d ", to[j] - m); 108 return 0; 109 }
View Code

[cogs729]圓桌問題(最大流)