1. 程式人生 > >POJ 3436 ACM Computer Factory 【最大流】

POJ 3436 ACM Computer Factory 【最大流】

<題目連結>

<轉載於 >>>  >

題目大意:

電腦公司生產電腦有N個機器,每個機器單位時間產量為Qi。 電腦由P個部件組成,每個機器工作時只能把有某些部件的半成品電腦(或什麼都沒有的空電腦)變成有另一些部件的半成品電腦或完整電腦(也可能移除某些部件)。求電腦公司的單位時間最大產量,以及哪些機器有協作關係,即一臺機器把它的產品交給哪些機器加工。

解題分析:

 最大流問題。

  首先是建圖。如果某臺機器對於放入其中的電腦的要求全為0或者2,那麼這臺機器就是一個源點,如果某臺機器生產出的電腦所有部分都為1,那麼這臺機器就可以看成一個匯點。這樣就有多個源點和多個匯點,那麼我們可以設定一個超級源點和超級匯點,超級源點指向每一個源點,每一個匯點指向超級匯點,流量限制為inf。對於每一臺機器,為了表示其效率上限,我們將其拆成兩個點,表示入口和出口,中間用一條流量限制為機器生存效率的線連線。而對於不同的機器,如果一臺機器生產出來的電腦能夠送往另一臺電腦,那麼就將這臺機器的出口指向另一臺機器的入口,流量限制為inf。建圖完成,其他的交給模板。

  另一個難點是要printf出最大流經過的路徑。那麼我們就可以來研究模板跑完以後留下的殘量網路。首先有三種路是我們為了方便解決問題而加入的,printf路徑的時候必須無視掉:從超級源點流出的路,流入超級匯點的路,由機器入口流到出口的路。那麼對於剩下的路,如果路上流量大於0,(或者說殘量小於流量限制),那麼這條路就是我們這個最大流網路中會經過的,打印出起點、終點和流量即可。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5
#include <queue> 6 using namespace std; 7 const int INF = 0x3f3f3f3f, maxn = 100 + 5; 8 struct node { 9 int s[12], t[12]; 10 int v; 11 }machine[55]; 12 13 //************************************************** 14 struct ans { 15 int from, to, num; 16 }ret[maxn];
17 struct Edge { 18 int from, to, cap, flow; 19 Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {} 20 }; 21 vector<int>ans[maxn]; 22 int len = 0, dis[maxn][maxn]; 23 struct Dinic { 24 int n, m, s, t; 25 vector<Edge> edges; 26 vector<int> G[maxn]; 27 bool vis[maxn]; 28 int dep[maxn]; 29 int cur[maxn]; 30 31 void init(int n) { 32 this->n = n; 33 for (int i = 0; i < n; i++)G[i].clear(); 34 edges.clear(); 35 } 36 void addedge(int from, int to, int cap) { 37 edges.push_back(Edge(from, to, cap, 0)); 38 edges.push_back(Edge(to, from, 0, 0)); 39 m = edges.size(); 40 G[from].push_back(m - 2); 41 G[to].push_back(m - 1); 42 } 43 bool BFS() { 44 memset(vis, 0, sizeof(vis)); 45 queue<int> Q; 46 Q.push(s); 47 dep[s] = 0; 48 vis[s] = 1; 49 while (!Q.empty()) { 50 int x = Q.front();Q.pop(); 51 for (int i = 0; i < G[x].size(); i++) { 52 Edge &e = edges[G[x][i]]; 53 if (!vis[e.to] && e.cap>e.flow) { 54 vis[e.to] = 1; 55 dep[e.to] = dep[x] + 1; 56 Q.push(e.to); 57 } 58 } 59 } 60 return vis[t]; 61 } 62 int DFS(int x, int a) { 63 if (x == t || a == 0) return a; 64 int flow = 0, f; 65 for (int &i = cur[x]; i < G[x].size(); i++) { 66 Edge &e = edges[G[x][i]]; 67 if (dep[x] + 1 == dep[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0) { 68 e.flow += f; 69 edges[G[x][i] ^ 1].flow -= f; 70 flow += f; 71 a -= f; 72 if (a == 0) break; 73 } 74 } 75 return flow; 76 } 77 int Maxflow(int s, int t) { 78 this->s = s;this->t = t; 79 int flow = 0; 80 while (BFS()) { 81 memset(cur, 0, sizeof(cur)); 82 flow += DFS(s, INF); 83 } 84 return flow; 85 } 86 }; 87 //dinic最大流模板 88 //**************************************************** 89 int main() { 90 int P, N; 91 Dinic temp; 92 scanf("%d%d", &P, &N); 93 temp.init(2 * N + 2); 94 for (int i = 1; i <= N; i++) { 95 scanf("%d", &machine[i].v); 96 for (int j = 0; j<P; j++)scanf("%d", &machine[i].s[j]); 97 for (int j = 0; j<P; j++)scanf("%d", &machine[i].t[j]); 98 bool sour = true; 99 for (int j = 0; j<P; j++) { 100 if (machine[i].s[j] == 1) { 101 sour = false; 102 break; 103 } 104 } 105 //構圖思想,0為超級源點,2*N+1為超級匯點 106 //因為每個機器都有流量限制,所以我們需要進行拆點,每個機器的兩個指標拆成兩點,兩點之間連一條為機器最大容納量的邊 107 if (sour)temp.addedge(0, i, INF); //如果該機器的第一指標全為0或2,說明該機器對放入其中的計算機無要求,所以作為源點,用超級源點與該源點連線 108 bool ending = true; 109 for (int j = 0; j<P; j++) { 110 if (machine[i].t[j] != 1) { 111 ending = false; 112 break; 113 } 114 } 115 if (ending) temp.addedge(i + N, 2 * N + 1, INF); //如果機器的第二個指標所有值均為1,則該機器的輸出符合要求,可以作為匯點,與超級匯點連一條容量為INF的邊 116 temp.addedge(i, i + N, machine[i].v); //該機器的第一指標與第二指標相連,容量為該機器的最大容量 117 } 118 //考慮不同機器的情況 119 for (int i = 1; i <= N; i++) { 120 for (int j = i + 1; j <= N; j++) { 121 bool yes1 = true, yes2 = true; 122 for (int k = 0; k<P; k++) { 123 if (machine[i].t[k]) { //i的出口不能與j的入口相連 124 if (machine[j].s[k] == 0) yes1 = false; 125 } 126 else { 127 if (machine[j].s[k] == 1) yes1 = false; 128 } 129 if (machine[j].t[k]) { //j的出口不能與i的入口相連 130 if (machine[i].s[k] == 0) yes2 = false; 131 } 132 else { 133 if (machine[i].s[k] == 1) yes2 = false; 134 } 135 if (!yes1&&!yes2)break; 136 } 137 if (yes1) 138 temp.addedge(i + N, j, INF); 139 if (yes2) 140 temp.addedge(j + N, i, INF); 141 } 142 } 143 printf("%d ", temp.Maxflow(0, 2 * N + 1)); 144 int cnt = 0; 145 146 for (int i = 0; i<temp.edges.size(); i++) { //記錄下所有符合要求的邊 147 Edge t = temp.edges[i]; 148 int fw = t.flow, f = t.from, tt = t.to; 149 //沒有流量的邊,和反向邊,和拆點之間的兩邊,和序號符合要求的邊 150 if (fw <= 0 || t.cap == 0 || t.cap != INF || tt>N || f<1) continue; //只有拆點的兩點之間容量不為INF 151 ret[cnt].from = f - N, ret[cnt].to = tt, ret[cnt].num = fw; 152 cnt++; 153 } 154 printf("%d\n", cnt); 155 for (int i = 0; i<cnt; i++) { 156 printf("%d %d %d\n", ret[i].from, ret[i].to, ret[i].num); 157 } 158 return 0; 159 }

 

 

2018-11-25