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

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

题意:

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

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

分析:

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

  1. 每个机器的最大生产速率是一定的。如果 a a a可以到 b b b,那么 a a a b b b的权值怎么决定呢?
    • 解决方案:插点法。对于第 i i i个节点新建一个节点(这里是 i + n i+n i+n)作为中转点,如果 i i i i + n i+n i+n的权值为第 i i i个机器的速率,且所有 i i i可以到达的点,替换成 i + n i+n i+n节点到达(权值设置为 i n f inf inf或者 i i i点的速率)。
  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\n",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\n",i-n,v,kit.cap[v][i]);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值