zoukankan      html  css  js  c++  java
  • [网络流24题]餐巾计划问题

    Description

    一个餐厅在相继的$N$天里,每天需用的餐巾数不尽相同,假设第$i$天需要$r_i$块餐巾$(iin[1,N])$.

    餐厅可以购买新的餐巾,每块餐巾的费用为$p$分;或者把旧餐巾送到快洗部,洗一块需$m$天,其费用为$f$分;或者送到慢洗部,洗一块需$n$天$(n>m)$,其费用为$w(w<f)$分.

    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗.但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量.
    试为餐厅合理地安排好$N$天中餐巾使用计划,使总的花费最小.

    Input

    第$1$行有$6$个正整数$N,p,m,f,n,w.N$是要安排餐巾使用计划的天数;$p$是每块新餐巾的费用;$m$是快洗部洗一块餐巾需用天数;$f$是快洗部洗一块餐巾需要的费用;$n$是慢洗部洗一块餐巾需用天数;$w$是慢洗部洗一块餐巾需要的费用.
    接下来的$N$行是餐厅在相继的$N$天里,每天需用的餐巾数.

    Output

    一行一个整数餐厅在相继的$N$天里使用餐巾的最小总花费.

    Sample Input

    3 10 2 3 3 2
    5
    6
    7

    Sample Output

    145

    HINT

    $n;leq;1000$

    Solution

    把第$i$天拆成两个点$x_i,y_i$,分别表示当天用完的和需要的.

    从$s$向$x_i$连一条容量为$r_i$,费用为$0$的有向边.

    从$y_i$向$t$连一条容量为$r_i$,费用为$0$的有向边.

    从$x_i$向$x_{i+1}$连一条容量为$+infty$,费用为$0$的有向边.(不在第$i$天洗的餐巾)

    从$x_i$向$y_{i+m}$连一条容量为$+infty$,费用为$f$的有向边.

    从$x_i$向$y_{i+n}$连一条容量为$+infty$,费用为$w$的有向边.

    求最小费用最大流.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 2005
    #define M 20005
    #define INF 1000000000
    using namespace std;
    struct graph{
        int nxt,to,f,w;
    }e[M];
    struct edge{
        int e,v;
    }pre[N];
    int g[N],dis[N],n,p,s,t,d1,w1,d2,w2,cnt=1;
    bool inq[N];
    queue<int> q;
    inline void addedge(int x,int y,int f,int w){
        e[++cnt].nxt=g[x];g[x]=cnt;
        e[cnt].to=y;e[cnt].f=f;e[cnt].w=w;
    }
    inline void adde(int x,int y,int f,int w){
        addedge(x,y,f,w);addedge(y,x,0,-w);
    }
    inline bool spfa(int u){
        for(int i=1;i<=t;++i){
            dis[i]=INF;inq[i]=false;
        }
        q.push(u);dis[u]=0;inq[u]=true;
        while(!q.empty()){
            u=q.front();q.pop();inq[u]=false;
            for(int i=g[u];i;i=e[i].nxt)
                if(e[i].f>0&&dis[u]+e[i].w<dis[e[i].to]){
                    dis[e[i].to]=dis[u]+e[i].w;
                    pre[e[i].to].e=i;pre[e[i].to].v=u;
                    if(!inq[e[i].to]){
                        q.push(e[i].to);inq[e[i].to]=true;
                    } 
                } 
        }
        return dis[t]<INF;
    }
    inline int mf(){
        int ret=0,d;
        while(spfa(s)){
            d=INF;
            for(int i=t;i!=s;i=pre[i].v)
                d=min(d,e[pre[i].e].f);
            ret+=d*dis[t];
            for(int i=t;i!=s;i=pre[i].v){
                e[pre[i].e].f-=d;
                e[pre[i].e^1].f+=d;
            }
        }
        return ret;
    }
    inline void Aireen(){
        scanf("%d%d%d%d%d%d",&n,&p,&d1,&w1,&d2,&w2);
        s=(n<<1)+1;t=s+1;
        for(int i=1,r;i<=n;++i){
            scanf("%d",&r);
            adde(s,i+n,INF,p);
            adde(s,i,r,0);
            adde(i+n,t,r,0);
        }
        for(int i=1;i<=n;++i){
            if(i<n) adde(i,i+1,INF,0);
            if(i+d1<=n) adde(i,i+d1+n,INF,w1);
            if(i+d2<=n) adde(i,i+d2+n,INF,w2);
        }
        printf("%d
    ",mf());
    }
    int main(){
        freopen("napk.in","r",stdin);
        freopen("napk.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    bzoj 1031: [JSOI2007]字符加密Cipher
    [BZOJ5011][JXOI2017]颜色
    [BZOJ4765]普通计算姬(分块+树状数组)
    [BZOJ3261]最大异或和(可持久化Trie)
    [BZOJ4861][BJOI2017]魔法咒语(AC自动机+矩阵优化DP)
    [BZOJ2286][SDOI2011]消耗战(虚树DP)
    [BZOJ2109][NOI2010]航空管制(贪心+拓扑)
    [BZOJ1305][CQOI2009]跳舞(网络流)
    [Nescafé41]编码病毒(循环卷积)
    [Nescafé41]异化多肽(多项式求逆元)
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6240957.html
Copyright © 2011-2022 走看看