博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 【中学高级本-网络流24题】餐巾计划

【中学高级本-网络流24题】餐巾计划

Description

一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。
(1)购买新的餐巾,每块需p分;
(2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。
(3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。
在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。

Input

共 3 行:
第 1 行为总天教;
第 2 行为每天所需的餐巾块数;
第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。

Output

一行,最小的费用

Sample Input

3
3 2 4
10 1 6 2 3

Sample Output

64

Hint

数据规模:
n<=200,Ri<=50

Source

网络流
线性规划网络优化,最小费用最大流

 
 

解析

这题也就是建图。。。

首先,我们要考虑拆点,

将一天拆成早上和晚上,

那么,每天早上,餐厅都会得到到干净的餐巾,

而餐巾则来自于购买,或是kt,mt天前的晚上(因为洗完了)(本题解中,kt为快洗天数,mt为慢洗天数,kp为快洗价格,mp为慢洗价格)。

而每天晚上,餐厅都将有X张旧餐巾产生,

而这些餐巾将会被快洗,慢洗,扔掉或是留到后一天晚上(第一次交的时候没考虑这种情况然后WA了)。

那么,我们就可以开始建图了!

首先,将源点与每天晚上连起来,流量为当天需要的餐巾数,费用为零,表示当天晚上收到的旧餐巾。

接下来,将每天晚上与kt,mt天后的早上连起来(大于n要特判),

流量为INF,费用为kp,mp,

表示洗完后的早上能得到洗的餐巾。

再将每天晚上与后一天晚上连起来,流量为INF,费用为零,表示将当天的旧餐巾放到第二天晚上再处理。

最后,将每天早上与汇点连起来,流量为当天的餐巾数,费用为零,表示当天早上收到的餐巾。

再跑最小费用最大流就行了!

 

 

上AC代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

inline ll read(){
    ll sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int INF=10000000000000;
struct node{
    int next,to;
    ll v,w;
}e[1000001];
struct hh{
    int fa,edge;
}pre[100001];
int n,m,s,t,a[100001];
int p,kp,kt,mp,mt;
int head[100001],cnt=1;
int inq[100001];
ll d[100001],mi[100001];

void add(int x,int y,int v,int w){
    e[++cnt].to=head[x];
    e[cnt].next=y;
    e[cnt].w=w;
    e[cnt].v=v;
    head[x]=cnt;
}

bool spfa(){
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n*2+3;i++) d[i]=INF;
    for(int i=1;i<=n*2+3;i++) mi[i]=INF;
    memset(inq,0,sizeof(inq));
    queue <int> que;
    que.push(s);
    d[s]=0;
    while(!que.empty()){
        int x=que.front();
        inq[x]=0;
        que.pop();
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(d[k]>d[x]+e[i].w&&e[i].v){
                d[k]=d[x]+e[i].w;
                pre[k].fa=x;
                pre[k].edge=i;
                mi[k]=min(mi[x],e[i].v);
                if(!inq[k]) que.push(k);
                inq[k]=1;
            }
        }
    }
    return d[t]!=INF;
}

void EK(){
    ll cost=0,ret;   
    while(spfa()){
        ret=mi[t];
        
        for(int i=t;i!=s;i=pre[i].fa){
            e[pre[i].edge].v-=ret;
            e[pre[i].edge^1].v+=ret;
        }    
        cost+=ret*d[t];
    }
    printf("%lld\n",cost);
    return ;
}

int main(){
    n=read();
    s=n*2+1;t=n*2+2;
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    p=read();kt=read();kp=read();mt=read();mp=read();
    for(int i=1;i<=n;i++){
        add(s,i,INF,p);
        add(i,s,0,-p);
        add(s,i+n,a[i],0);
        add(i+n,s,0,0);
        if(i+kt<=n){
            add(i+n,i+kt,INF,kp);
            add(i+kt,i+n,0,-kp);
        }
        if(i+mt<=n){
            add(i+n,i+mt,INF,mp);
            add(i+mt,i+n,0,-mp);
        }
        add(i,t,a[i],0);
        add(t,i,0,0);
        if(i<n){
            add(i+n,i+1+n,INF,0);
            add(i+1+n,i+n,0,0);
        }
    }
    EK();
    return 0;
}

 

posted @ 2019-03-12 14:11  Hastin  阅读(233)  评论(0编辑  收藏  举报