zoukankan      html  css  js  c++  java
  • 洛谷1251 餐巾计划问题

    题目链接:餐巾计划问题

    分析:

    对于每一天,我们把它拆成两个点,分别代表每一天用完的餐巾(x_i)和每一天需要的纸巾(y_i)

    接下来就是根据题意建图,首先建立源点(s)和汇点(t)

    由于题目中每一天都需要(r_i)张餐巾,我们可以由(s)向所有的(x_i)连一条容量为(r_i),费用为0的边;

    再从所有的(y_i)(t)连一条容量为(r_i),费用为0的边,我们希望这些边在最后没有剩余容量

    接下来就是根据题目中对纸巾的处理方式来建图

    1、什么都不做——由(x_i)(x_{i+1})连一条容量为(r_i),费用为0的边

    2、送至快洗店——由(x_i)(y_{i+m})连一条容量为INF,费用为(f)的边

    3、送至慢洗店——由(x_i)(y_{i+n})连一条容量为INF,费用为(s)的边

    4、购买——由(s)(y_i)连一条容量为INF,费用为(p)的边

    那么在加入这四种边之后能否使我们先前的所有边跑满呢?

    答案是显然的——新加入的边的容量为INF,根据流量平衡,会有在前两种边跑满的情况下后面的边仍未跑满的情况

    因此直接费用流即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    #define int long long
    #define maxd 1e18+7
    struct node{
        int to,nxt,cost,flow;
    }sq[200200];
    int n,r[200050],t1,w1,t2,w2,all=1,head[200050],s,t,p,flow[205000],
        dis[200050],pre[200050],minc=0;
    bool vis[200050];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    void add(int u,int v,int f,int w)
    {
        all++;sq[all].to=v;sq[all].nxt=head[u];sq[all].flow=f;sq[all].cost=w;head[u]=all;
        all++;sq[all].to=u;sq[all].nxt=head[v];sq[all].flow=0;sq[all].cost=-w;head[v]=all;
    }
    
    void init()
    {
        n=read();int i;
        s=1;t=2*n+2;
        for (i=1;i<=n;i++) r[i]=read();
        p=read();t1=read();w1=read();t2=read();w2=read();
        for (i=1;i<=n;i++)
        {
            add(s,i+1,r[i],0);add(i+n+1,t,r[i],0);
            if (i<n) add(i+1,i+2,maxd,0);
            if (i+t1<=n) add(i+1,i+n+t1+1,maxd,w1);
            if (i+t2<=n) add(i+1,i+n+t2+1,maxd,w2);
            add(s,i+n+1,maxd,p);
        }
    }
    
    bool spfa()
    {
        queue<int> q;int i;
        memset(vis,0,sizeof(vis));
        memset(flow,0,sizeof(flow));
        memset(pre,0,sizeof(pre));
        for (i=1;i<=t;i++) dis[i]=maxd;
        dis[s]=0;q.push(s);vis[s]=1;flow[s]=maxd;
        while (!q.empty())
        {
            int u=q.front();q.pop();vis[u]=0;
            for (i=head[u];i;i=sq[i].nxt)
            {
                int v=sq[i].to;
                if ((sq[i].flow) && (dis[u]+sq[i].cost<dis[v]))
                {
                    dis[v]=dis[u]+sq[i].cost;
                    pre[v]=i;
                    flow[v]=min(flow[u],sq[i].flow);
                    if (!vis[v])
                    {
                        q.push(v);vis[v]=1;
                    }
                }
            }
        }
        return (dis[t]!=maxd);
    }
    
    void update()
    {
        int now=t;minc+=(flow[t]*dis[t]);
        while (now!=s)
        {
            int tmp=pre[now];
            sq[tmp].flow-=flow[t];
            sq[tmp^1].flow+=flow[t];
            now=sq[tmp^1].to;
        }
    }
    
    void work()
    {
        while (spfa()) update();
        printf("%lld",minc);
    }
    signed main()
    {
        init();
        work();
        return 0;
    }
    
    
  • 相关阅读:
    生产环境Crontab专业实例
    Linux系统定时任务介绍
    Linux文件属性改变命令chown-chgrp-chattr-lsattr实践
    Linux命令总结
    Linux特殊权限位suid、sgid深度详细及实践
    企业场景-网站目录安全权限深度讲解及umask知识
    shell简介
    Nginx模块及配置虚拟主机
    安装Nginx
    Nginx简介
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10127010.html
Copyright © 2011-2022 走看看