zoukankan      html  css  js  c++  java
  • P1251 餐巾计划问题

    传送门

    想象一下餐巾的转移,从前一天到后一天,从外面买来,送到其他地方去洗然后过几天回来

    发现很像一个流

    所以考虑构建网络流模型

    建立一个源点 $S$ ,和汇点 $T$

    然后显然我们要按时间拆点,把每天的餐馆拆成早上和晚上,早上送走干净餐巾,晚上得到脏餐巾

    每天早上向 $T$ 连一条流量为当天餐巾需求量,费用为 $0$ 的边,如果满流说明当天餐巾够用了

    注意餐巾不能就这样流到汇点消失,因为脏餐巾还可以洗了再用,所以从 $S$ 向晚上连一条流量为当天餐巾需求量,费用为 $0$ 的边(要注意源点流到晚上的的餐巾表示的是脏餐巾)

    考虑购买餐巾,从 $S$ 连到每天早上,流量为 $INF$,费用为餐巾单价的边

    然后考虑快洗,从晚上连一条流量为 $INF$ ,费用为快洗费用的边到对应的时间点的早上

    慢洗同理

    因为脏餐巾可以留着到下一天,所以每天晚上连到下一天晚上,流量 $INF$ ,费用为 $0$

    早上同理

    然后跑费用流,注意开 $long long$

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long ll;
    inline 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<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7,iNF=1e9+7;
    const ll INF=1e18+7;
    int fir[N],from[N<<2],to[N<<2],val[N<<2],cst[N<<2],cntt=1;
    inline void add(int a,int b,int c,int d)
    {
        from[++cntt]=fir[a]; fir[a]=cntt;
        to[cntt]=b; val[cntt]=c; cst[cntt]=d;
        from[++cntt]=fir[b]; fir[b]=cntt;
        to[cntt]=a; val[cntt]=0; cst[cntt]=-d;
    }
    int Nn,S,T;
    int mif[N],pre[N];
    ll dis[N];
    queue <int> q;
    bool inq[N];
    bool SPFA()
    {
        for(int i=1;i<=T;i++) dis[i]=INF;
        q.push(S); inq[S]=1; dis[S]=0; mif[S]=iNF;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); inq[x]=0;
            for(int i=fir[x];i;i=from[i])
            {
                int &v=to[i]; if(!val[i] || dis[v]<=dis[x]+cst[i]) continue;
                dis[v]=dis[x]+cst[i]; pre[v]=i;
                mif[v]=min(mif[x],val[i]);
                if(!inq[v]) q.push(v),inq[v]=1;
            }
        }
        return dis[T]<INF;
    }
    ll ans;
    inline void upd()
    {
        for(int now=T,i=pre[T]; now!=S; now=to[i^1],i=pre[now])
            val[i]-=mif[T],val[i^1]+=mif[T];
        ans+=dis[T]*mif[T];
    }
    //以上为费用流模板
    int main()
    {
        int a;
        Nn=read(); S=(Nn<<1)+1,T=(Nn<<1)+2;
        for(int i=1;i<=Nn;i++)
        {
            a=read();
            add(S,i,a,0); add(i+Nn,T,a,0);//源点向晚上连,早上向汇点连
        }
        int p,m,f,n,s;
        p=read(),m=read(),f=read(),n=read(),s=read();
        for(int i=1;i<=Nn;i++)
        {
            add(S,i+Nn,iNF,p);//购买餐巾
            if(i+1<=Nn) add(i,i+1,iNF,0),add(i+Nn,i+Nn+1,iNF,0);//时间的转移
            if(i+m<=Nn) add(i,i+Nn+m,iNF,f);//快洗
            if(i+n<=Nn) add(i,i+Nn+n,iNF,s);//慢洗
        }
        while(SPFA()) upd();
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    浅谈Android系统开发中LOG的使用
    在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
    美国地名大全(美国城市名称英文、中文)
    简单工厂模式
    Union和Union All的差别
    strlen和sizeof的差别
    css+div网页设计(一)--基础知识
    Java程序猿面试题集(181- 199)
    【Android XMPP】 学习资料收集贴(持续更新)
    curl命令具体解释
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10351070.html
Copyright © 2011-2022 走看看