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

猜你喜欢

转载自www.cnblogs.com/00isok/p/10016918.html