zoukankan      html  css  js  c++  java
  • ACM Computer Factory(网络流 POJ 3436,这可是我第一次写网络流)

    ACM Computer Factory(网络流 POJ 3436,这可是我第一次写网络流)

    题意:

    有n台机器,每台机器有一个输入规则和输出规则 和一个最大生产速率,且每个输出和输出的属性有q个。
    

    且对于机器的输入规则状态0代表没有,1代表必须有,2代表无所谓,输出规则的状态只有0 和1。现在让你求怎么样才能让流水线生产出最终产品的速率最大。

    分析:

    ​ 这是一个网络流的模型,我们可以把机器作为节点, 然后设置一个超级源点begbeg,让所有输入为0 0 0 0 0(2也行)连接到超级源点begbeg,权值设为infinf, 再设置一个超级汇点,让所有输入1 1 1 1 1的连接到超级汇点endend 权值设为infinf。然后遍历所有机器,如果aa可以到bb ,则设置一条边(权值后面再讨论)。不过可能要注意下面几个问题

    1. 每个机器的最大生产速率是一定的。如果aa可以到bb,那么aabb的权值怎么决定呢?
      • 解决方案:插点法。对于第ii个节点新建一个节点(这里是i+ni+n)作为中转点,如果iii+ni+n的权值为第ii个机器的速率,且所有ii可以到达的点,替换成i+ni+n节点到达(权值设置为infinf或者ii点的速率)。
    2. 然后网络流模型即可解决。

    代码:(EK算法+邻接表实现)

    #include<bits/stdc++.h>
    #define mset(a,b)   memset(a,b,sizeof(a))
    using namespace std;
    typedef unsigned long long ull;
    typedef long long ll;
    const int maxn=120;
    const int inf=0x7fffffff;
    struct Edge
    {
        int to;
        bool is_have;//是否有这个边 在初始的流浪网络中
    };
    struct Machine{
        int a[15],b[15],cap;
    }machin[100];
    int p,n;
    class EdmondsKarp
    {
        /*要求输入:顶点数和边即可*/
    public:
        int flow;
        vector<Edge> adja[maxn];/*邻接表遍历边*/
        int cap[maxn][maxn];/*存取容量*/
        int pre[maxn];
        int dismin[maxn];
        int tot;
        /*输入顶点的个数 添加边*/
        void Init(int n)//初始化
        {
            for(int i=0; i<n; ++i) //边从1=0开始标号
                adja[i].clear();
            mset(cap,0);
            tot=n;
        }
        void AddEdge(int u,int v,int c)//又该边
        {
            /* 两个方向加上边 不给过属性不同,*/
            Edge nowe;
            cap[u][v]=c;
            cap[v][u]=0;
            nowe.to=v;
            nowe.is_have=1;//原图中有这边
            adja[u].push_back(nowe);
            nowe.to=u;
            nowe.is_have=0;//原图中没有这边
            adja[v].push_back(nowe);
        }
        int MaxFlow(int s,int t)
        {
            queue<int> mmp;
    
            flow=0;
            for(;;)
            {
                for(int i=0; i<tot; ++i)
                {
                     pre[i]=-1;
                     dismin[i]=inf;//s到i的最短路的流量最小值
                }
                pre[s]=0;//等于u
                mmp.push(s);
                while(!mmp.empty())
                {
                    int nowu=mmp.front();
                    mmp.pop();
                    for(int i=0; i<adja[nowu].size(); ++i)
                    {
                        int nowv=adja[nowu][i].to;
                        if(pre[nowv]==-1&&cap[nowu][nowv]>0)
                        {
                            pre[nowv]=nowu;
                            mmp.push(nowv);
                            dismin[nowv]=min(dismin[nowu],cap[nowu][nowv]);
                        }
                    }
                }
                if(pre[t]==-1)
                    return flow;
                /*有一条增广路径  顺着这条增广路径一直把边的容量改变*/
                flow+=dismin[t];
                int lastu,now;
                now=t;
                while(now!=s)
                {
                    lastu=pre[now];
                    cap[lastu][now]-=dismin[t];
                    cap[now][lastu]+=dismin[t];
                    now=lastu;
                }
            }
        }
    };
    EdmondsKarp kit;
    bool judge(int i,int j)//i能否到j
    {
        for(int t=0;t<p;++t)
        {
            if(machin[j].a[t]!=2&&machin[i].b[t]!=machin[j].a[t])
            {
                return 0;
            }
        }
        return 1;
    }
    bool IsBeginOut(int i)//看需要的输入是不是全为0
    {
        for(int j=0;j<p;++j)
        {
            if(machin[i].a[j]==1)
                return false;
        }
        return true;
    }
    bool IsArrivedIn(int i)
    {
        for(int j=0;j<p;++j)
        {
            if(machin[i].b[j]!=1)
                return false;
        }    return true;
    }
    int main()
    {
        scanf("%d%d",&p,&n);
        kit.Init(2*n+2);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&machin[i].cap);
            for(int j=0;j<p;++j)
                scanf("%d",machin[i].a+j);
            for(int j=0;j<p;++j)
                scanf("%d",machin[i].b+j);
            kit.AddEdge(i,i+n,machin[i].cap);
            if(IsBeginOut(i))
                kit.AddEdge(0,i,machin[i].cap);
            if(IsArrivedIn(i))
            {
                kit.AddEdge(i+n,2*n+1,machin[i].cap);
            }
    
        }
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                if(i==j)
                    continue;
                if(judge(i,j))
                    kit.AddEdge(i+n,j,inf);
            }
        }
        int res=kit.MaxFlow(0,2*n+1);
        int tot=0;
        for(int i=n+1;i<=2*n;++i)
        {
            for(int j=0;j<kit.adja[i].size();++j)
            {
                int v=kit.adja[i][j].to;
                if(kit.adja[i][j].is_have=true&&v>=1&&v<=n&&i!=v+n&&kit.cap[v][i]>0)
                    tot++;
            }
        }
        printf("%d %d
    ",res,tot);
        for(int i=n+1;i<=2*n;++i)
        {
            for(int j=0;j<kit.adja[i].size();++j)
            {
                int v=kit.adja[i][j].to;
                if(kit.adja[i][j].is_have=true&&v>=1&&v<=n&&i!=v+n&&kit.cap[v][i]>0)
                   printf("%d %d %d
    ",i-n,v,kit.cap[v][i]);
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    BZOJ 1027: [JSOI2007]合金 (计算几何+Floyd求最小环)
    BZOJ 4522: [Cqoi2016]密钥破解 (Pollard-Rho板题)
    BZOJ 4802: 欧拉函数 (Pollard-Rho)
    BZOJ 3944: Sum (杜教筛)
    BZOJ 3309: DZY Loves Math (莫比乌斯反演)
    BZOJ 2599: [IOI2011]Race(点分治板题)
    BZOJ 3680: 吊打XXX // Luogu [JSOI2004]平衡点 / 吊打XXX (模拟退火)
    Luogu P3690【模板】Link Cut Tree (LCT板题)
    [HNOI2007]最小矩形覆盖
    [SCOI2007]最大土地面积
  • 原文地址:https://www.cnblogs.com/dchnzlh/p/10546540.html
Copyright © 2011-2022 走看看