题解:餐巾计划问题

传送门

一个餐厅在相继的 NNN 天里,每天需用的餐巾数不尽相同。假设第 iii 天需要 rir_iri​块餐巾( i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 ppp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nnn 天(n>mn>mn>m),其费用为 sss 分(s<fs<fs<f)、
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 NNN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

这个题目是一个费用流的题目
首先我们要把每一天拆成早上和晚上两个点
连边如下:

  • 晚上从起点获得x条脏餐巾,从原点向每一天晚上连一条流量为当天所用餐巾x,费用为0的边。
  • 白天向汇点提供x条干净的餐巾,从每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边 。
  • 晚上可以将脏餐巾留到第二天晚上,从每一天晚上向第二天晚上连一条流量为INF,费用为0的边
  • 晚上可以送去快洗部,在地i+t1天早上收到餐巾 ,从每一天晚上向这一天+快洗所用天数t1的那一天早上连一条流量为INF,费用为快洗所用钱数的边
  • 晚上可以送去慢洗部,在地i+t2天早上收到餐巾 ,从每一天晚上向这一天+慢洗所用天数t2的那一天早上连一条流量为INF,费用为慢洗所用钱数的边
  • 每天早上可以购买餐巾,从起点向每一天早上连一条流量为INF,费用为购买餐巾所用钱数的边

建好了图之后,就可以直接套上费用流的模板跑最大流了

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
#define re register
#define gc getchar()
#define ll long long
#define il inline
il ll read() {
    re ll x(0),f(1);
    re char ch=gc;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=gc;
    }
    while(ch>='0'&&ch<='9') {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=gc;
    }
    return x*f;
}
inline ll min(ll a,ll b) {
    return a<b?a:b;
}
const ll INF=(1<<29),N=100010;
struct node {
    ll to,next,w,c;
} e[N];
ll h[N],cnt=1,n,s,t;
inline void add(ll u,ll v,ll w,ll c) {
    e[++cnt]=(node) {v,h[u],w,c},h[u]=cnt;
    e[++cnt]=(node) {u,h[v],0,-c},h[v]=cnt;
}
#define QXX(u) for(ll i=h[u],y;y=e[i].to,i;i=e[i].next)
ll dis[N],vis[N],pre[N],f[N],maxf,minc,m;

ll spfa() {
    for(ll i=1; i<=t; ++i) dis[i]=INF,vis[i]=0;
    std::queue<ll> q;
    while(!q.empty()) q.pop();
    q.push(s);
    vis[s]=1,dis[s]=0,pre[t]=-1,f[s]=INF;
    while(!q.empty()) {
        ll x=q.front();
        q.pop();
        vis[x]=0;
        QXX(x) {
            if(!e[i].w) continue;
            if(dis[y]>dis[x]+e[i].c) {
                dis[y]=dis[x]+e[i].c;
                f[y]=min(f[x],e[i].w);
                pre[y]=i;
                if(!vis[y]) vis[y]=1,q.push(y);
            }
        }
    }
    return pre[t]==-1?-1:f[t];
}
void dinic () {
    ll x,in,y;
    while ((in=spfa ())!=-1) {
        x=t;
        while (x!=s) {
            y=pre[x];
            e[y].w-=in;
            e[y^1].w+=in;
            x=e[y^1].to;
        }
        maxf+=in;
        minc+=in*dis[t];
    }
    cout<<minc<<endl;
}

int main() {

    scanf("%d",&n);
    s=0,t=2*n+1;
    for(ll i=1; i<=n; i++) {
        ll x=read();
        add(s,i,x,0);
        add(i+n,t,x,0);
    }
    ll m=read(),t1=read(),m1=read(),t2=read(),m2=read();
    for(ll i=1; i<=n; i++) {
        if(i+1<=n) add(i,i+1,INF,0);
        if(i+t1<=n) add(i,i+n+t1,INF,m1);
        if(i+t2<=n) add(i,i+n+t2,INF,m2);
        add(s,i+n,INF,m);
    }
    dinic();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/87817971