<题目链接>
<转载于 >>> >
题目大意:
电脑公司生产电脑有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