POJ-3436 ACM Computer Factory---最大流+拆点

题目链接:

https://vjudge.net/problem/POJ-3436

题目大意:

每台电脑有p个组成部分,有n个工厂加工电脑。每个工厂对于进入工厂的半成品的每个组成部分都有要求,由p个数字描述,0代表这个部分不能有,1代表这个部分必须有,2代表这个部分的有无无所谓。每个工厂的产出也不尽相同,也是由p个数字代表,0代表这个部分不存在,1代表这个部分存在。每个工厂都有一个最大加工量。给出这n个工厂的以上数据,求出最多能加工出多少台电脑。

解题思路:

这道题主要是如何建设出网络出来,每个工厂表示一个点

 

1、首先对每个点进行拆分,拆成i(输入部分)和n+i(输出部分),之间连接一条边,权值为这个点的加工量(拆点这个技巧是为了维护点的权值)

 

2、对每个点的输入部分(i),如果没有一,那就从超级源点s出发,连一条边到该点,权值为这个点的加工量。(因为只有全是0,或者是0或2没有1,那才是整个工厂的出发点)(此处不要忘记2的存在,一开始只把全是0的和超级源点s建边,后来想到只要没有1,都可以建边)

 

3、对于每个点的输出部分(n + i),如果全是1,说明已经建好,和超级汇点建边,权值为这个点的加工量

 

4、对于每个点的输出部分(n + i),只要满足其他点的输入部分,这两点之间可以建立边,权值设置成INF(这里设置成INF的目的是为了最后输出答案中的边,便于寻找这些边,只要权值为INF的边且流量不为0,那么这条边就可以输出)

 

然后就是从源点s到汇点t的最大流(传送门:最大流模板

  1 #include<iostream>
  2 #include<vector>
  3 #include<cstring>
  4 #include<queue>
  5 using namespace std;
  6 const int maxn = 100 + 10;
  7 const int INF = 0x3f3f3f3f;
  8 int n, m;
  9 struct edge
 10 {
 11     int u, v, c, f;
 12     edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){}
 13 };
 14 vector<edge>e;
 15 vector<int>Map[maxn];
 16 int a[maxn], p[maxn];
 17 void init(int n)
 18 {
 19     e.clear();
 20     for(int i = 0; i <= n; i++)Map[i].clear();
 21 }
 22 void addedge(int u, int v, int c)
 23 {
 24     //cout<<u<<" "<<v<<" "<<c<<endl;
 25     e.push_back(edge(u, v, c, 0));
 26     e.push_back(edge(v, u, 0, 0));
 27     int m = e.size();
 28     Map[u].push_back(m - 2);
 29     Map[v].push_back(m - 1);
 30 }
 31 int Maxflow(int s, int t)
 32 {
 33     int flow = 0;
 34     for(;;)
 35     {
 36         memset(a, 0, sizeof(a));
 37         queue<int>q;
 38         q.push(s);
 39         a[s]  =INF;
 40         while(!q.empty())
 41         {
 42             int u = q.front();
 43             q.pop();
 44             for(int i = 0; i < Map[u].size(); i++)
 45             {
 46                 edge& now = e[Map[u][i]];
 47                 int v = now.v;
 48                 if(!a[v] && now.c > now.f)//还未流经并且边还有容量
 49                 {
 50                     p[v] = Map[u][i];
 51                     a[v] = min(a[u], now.c - now.f);
 52                     q.push(v);
 53                 }
 54             }
 55             if(a[t])break;//已经到达汇点
 56         }
 57         if(!a[t])break;//已经没有增广路
 58         for(int u = t; u != s; u = e[p[u]].u)
 59         {
 60             e[p[u]].f += a[t];
 61             e[p[u] ^ 1].f -= a[t];
 62         }
 63         flow += a[t];
 64     }
 65     return flow;
 66 }
 67 int cnt[maxn][maxn];
 68 vector<edge>ans;
 69 int main()
 70 {
 71     cin >> m >> n;
 72     for(int i = 1; i <= n; i++)
 73     {
 74         for(int j = 0; j <= 2 * m; j++)cin >> cnt[i][j];
 75     }
 76     int s = 0, t = 2 * n + 1;
 77     for(int i = 1; i <= n; i++)
 78     {
 79         int tot1 = 0, tot2 = 0;
 80         for(int j = 1; j <= m; j++)tot1 += cnt[i][j] == 1 ? 1 : 0;//此处只要没有1,就可以和s建边
 81         for(int j = m + 1; j <= 2 * m; j++)tot2 += cnt[i][j];//此处全为1就可以和t建边
 82         addedge(i, i + n, cnt[i][0]);
 83         if(tot1 == 0)addedge(s, i, cnt[i][0]);
 84         if(tot2 == m)//和t建边之后没必要寻找其他点建边
 85         {
 86             addedge(i + n, t, cnt[i][0]);
 87             continue;
 88         }
 89         for(int j = 1; j <= n; j++)
 90         {
 91             if(i == j)continue;
 92             int flag = 1;
 93             for(int k = 1; k <= m; k++)
 94             {
 95                 if(cnt[j][k] == 0 && cnt[i][m + k] != 0)//第j个点的第k个值为0,说明不需要第k个元件,那么第i个点的第k原件输出只能为0
 96                 {
 97                     flag = 0;
 98                     break;
 99                 }
100                 if(cnt[j][k] == 1 && cnt[i][m + k] != 1)//第j个点的第k个值为1,说明需要第k个元件,那么第i个点的第k原件输出只能为1
101                 {
102                     flag = 0;
103                     break;
104                 }
105             }
106             if(flag)addedge(i + n, j, INF);//ij可以建边,设置成INF
107         }
108     }
109     cout<<Maxflow(s, t)<<" ";
110     for(int i = 0; i < e.size(); i += 2)//此处+=2,是因为最大流有反向边
111     {
112         //cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].c<<" "<<e[i].f<<endl;
113         if(e[i].c == INF && e[i].f > 0)
114         {
115             ans.push_back(e[i]);
116         }
117     }
118     cout<<ans.size()<<endl;
119     for(int i = 0; i < ans.size(); i++)
120     {
121         cout<<ans[i].u - n<<" "<<ans[i].v<<" "<<ans[i].f<<endl;
122     }
123 }

 

posted @ 2018-04-17 22:30  _努力努力再努力x  阅读(252)  评论(0编辑  收藏  举报