zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    【转】全文检索引擎Sphinx配置文件详细介绍
    【转】构建不依赖于cookie的手机端用户登录机制
    Sphinx在window下的初步安装和配置
    Zend Framework 在.htaccess中修改RewriteRule实现url重写
    做后台的程序猿的一点心得
    [Leetcode 75] 96 Unique Binary Search Trees
    [Leetcode 74] 92 Restore IP Addresses
    [Leetcode 73] 92 Reverse Linked List II
    [Leetcode 72] 91 Decode Ways
    [Leetcode 71] 86 Partition List
  • 原文地址:https://www.cnblogs.com/fzl194/p/8870457.html
Copyright © 2011-2022 走看看