P1251 餐巾计划问题

【题意】

 

 【分析】

这是一道很好的的拆点建图的费用流,首先这个餐巾因为要分干净和脏的,所以容易想到拆点的做法

然后呢,这个建图就很神了

我们把每一天拆成两个点,晚上和上午

1.S->晚上 和 上午->T ,建立(ri,0)表示晚上接受ri脏餐巾,白天花费ri干净餐巾,费用均为0

2.i天晚上->i+1天晚上,建立(inf,0)表示晚上的脏餐巾可以留任意多个不洗,费用为0

3.S->上午,建立(inf,p)表示可以直接购买干净的餐巾

4.i天晚上->i+m天上午,建立(inf,f)表示可以送到快洗店

5.i天晚上->i+n天上午,建立(inf,s)表示送到慢洗店

 

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int maxn=4000+5;
int n,head[maxn],s,t;
struct edge
{
    int to,nxt;
    ll v,cost;
}e[maxn*20];
int cnt=1;
void add(int x,int y,ll z,ll zz)
{
    e[++cnt].nxt=head[x]; e[cnt].to=y; e[cnt].v=z; e[cnt].cost=zz; head[x]=cnt;
    e[++cnt].nxt=head[y]; e[cnt].to=x; e[cnt].v=0; e[cnt].cost=-zz; head[y]=cnt;
}
ll dis[maxn];
int vis[maxn],pre[maxn];
bool bfs()
{
    queue <int> q;
    q.push(s);
    for(int i=s;i<=t;i++) dis[i]=inf,vis[i]=0;
    dis[s]=0; vis[s]=1;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(dis[to]>dis[u]+e[i].cost && e[i].v)
            {
                dis[to]=dis[u]+e[i].cost;
                pre[to]=i;
                if(!vis[to]) q.push(to),vis[to]=1;
            }
        }
    }
    for(int i=s;i<=t;i++) vis[i]=0;
    return (dis[t]!=inf);
}
ll mincost,r[maxn];
void mcmf()
{
    while(bfs())
    {
        ll minn=inf;
        for(int i=t;i!=s;i=e[pre[i]^1].to)
            minn=min(minn,e[pre[i]].v);
        for(int i=t;i!=s;i=e[pre[i]^1].to)
        {
            e[pre[i]].v-=minn;
            e[pre[i]^1].v+=minn;
            mincost+=minn*e[pre[i]].cost;
        }
    }
}
int used[maxn],unused[maxn];
int main() 
{
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    scanf("%d",&n);
    s=1; t=2*n+2;
    for(int i=1;i<=n;i++) scanf("%lld",&r[i]);
    ll a,b,c,d,e;
    scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e);
    int tot=1;
    for(int i=1;i<=n;i++)
        unused[i]=++tot,used[i]=++tot;
    for(int i=1;i<=n;i++) 
    {
        add(s,unused[i],inf,a); //
        add(unused[i],t,r[i],0); //
        add(s,used[i],r[i],0);
        if(used[i+1]<=tot) add(used[i],used[i+1],inf,0);
        if(unused[i+b]<=tot) add(used[i],unused[i+b],inf,c);
        if(unused[i+d]<=tot) add(used[i],unused[i+d],inf,e); 
    }
    mcmf();
    printf("%lld",mincost);
    return 0;
}

 

posted @ 2021-06-06 11:39  andyc_03  阅读(55)  评论(0编辑  收藏  举报