洛谷P1251餐巾计划问题

题目

洛谷P1251餐巾计划问题

题解

拆点,一个点表示一天开始,另一个点表示一天结束,具体建图方法见注释。

然后用EK算法跑费用流。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn=5000;
const int maxm=500000;
const int inf=0x7fffffff;
const ll llinf=0x7ffffffffffff;
int n,m,s,t,day,tot=1,max_flow,p,t1,t2,p1,p2;
ll min_cost;
int r[maxn],head[maxn],pre[maxm],re[maxn];        //r[i]表示第i天需要的纸巾
ll d[maxn];
bool inq[maxn]; 
queue<int> q;
struct edge{int to,nxt,cap,flow,cost;}e[maxm];
inline void add(int from,int to,int cap,int cost)
{
    e[++tot].cap=cap; e[tot].to=to; e[tot].cost=cost;
    e[tot].nxt=head[from]; head[from]=tot;
}
inline int read()
{ 
    int s1=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') s1=(s1<<1)+(s1<<3)+(ch^48),ch=getchar();
    return s1;
}
inline void make_graph()
{
    s=maxn-1; t=maxn-2;
    for(int i=1;i<=day;i++) add(s,i<<1,inf,p),add(i<<1,s,0,-p);    //早上买纸巾 
    for(int i=1;i<day;i++) add(i<<1|1,(i+1)<<1|1,inf,0),add((i+1)<<1|1,i<<1|1,0,0);    
    //把脏纸巾从第一天晚上保留到第二天晚上,注意区分干净纸巾和脏纸巾 
    for(int i=1;i<=day;i++) add(s,i<<1|1,r[i],0),add(i<<1|1,s,0,0);    //晚上得到脏纸巾 
    for(int i=1;i<=day;i++) add(i<<1,t,r[i],0),add(t,i<<1,0,0);    //每天早上向汇点提供纸巾,流满时表示够用 
    for(int i=1;i<=day;i++) if(i+t1<=day) add(i<<1|1,(i+t1)<<1,inf,p1),add((i+t1)<<1,i<<1|1,0,-p1);
    //快洗,晚上开始洗,早上收到 
    for(int i=1;i<=day;i++) if(i+t2<=day) add(i<<1|1,(i+t2)<<1,inf,p2),add((i+t2)<<1,i<<1|1,0,-p2); //慢洗
}
inline bool spfa()
{
    for(int i=1;i<maxn;i++) d[i]=llinf;    //注意不要写成<=,否则会占用非法空间 
    d[s]=0; re[s]=inf;
    q.push(s); inq[s]=1;
    while(q.size())
    {
        int x=q.front(); q.pop(); 
        inq[x]=0;    //注意别忘了 
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(e[i].cap>e[i].flow&&d[y]>d[x]+(ll)e[i].cost)
            {
                d[y]=d[x]+(ll)e[i].cost;
                re[y]=min(re[x],e[i].cap-e[i].flow);
                pre[y]=i; 
                if(inq[y]) continue;
                inq[y]=1; q.push(y);
            }
        }
    }
    return d[t]<llinf;
}
inline void upd()
{
    max_flow+=re[t];
    min_cost+=(ll)re[t]*d[t];
    int x=t;
    while(x!=s)
    {
        int i=pre[x];
        e[i].flow+=re[t];
        e[i^1].flow-=re[t];
        x=e[i^1].to;
    }
}
inline void EK()
{
    while(spfa()) upd();
    printf("%lld\n",min_cost);
}

int main()
{
    //freopen("test2019.in","r",stdin);
    //freopen("test2019.out","w",stdout);
    day=read();
    for(int i=1;i<=day;i++) r[i]=read();
    p=read(),t1=read(),p1=read(),t2=read(),p2=read();
    make_graph();
    EK();
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zjgmartin/p/10381827.html