、

P1251 餐巾计划问题

题意

\(N\) 天,每天需要 \(r_i\) 个餐巾,用完后变成脏的。可以花费 \(p\) 买一条,或者花费 \(f\) 在 \(m\) 天后获得一条,或者花费 \(s\) 在 \(n\) 天后花费一条,或者留着,求最小花费。

思路

考虑网络流。我们可以将一天拆为两个点,分别为早上和晚上,这样我们就可以区分出哪个点需要送出和哪个点可以存起来了。那么将早上和 \(T\) 连一个 \((r_i,0)\) 代表需要贡献出这么多脏的,然后因为这个会消失吗,所以再连 \(S\) 和晚上 \((r_i,0)\) 表示收到这么多脏的。那么留到第二天晚上就连 \((\inf,0)\),两个花费就对应从晚上连到早上即可。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;
typedef long long ll;
const int MAXN=4e3+5;
const ll INFLL=1e17;
const int INF=2e9;
struct node{
    int v,w,nxt;
    ll c;
}e[MAXN*20];
int head[MAXN],tot=1;
void add_one(int u,int v,int w,int c){
    e[++tot]={v,w,head[u],c};
    head[u]=tot;
}
void add(int u,int v,int w,int c){
    add_one(u,v,w,c);
    add_one(v,u,0,-c);
}
int S,T,arc[MAXN];
ll dep[MAXN];
bool vs[MAXN],inq[MAXN];
bool spfa(){
    rep(i,S,T){
        dep[i]=INFLL;
        arc[i]=head[i];
        inq[i]=false;
    }
    queue<int>que;
    que.push(S);
    dep[S]=0;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        inq[u]=false;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].v;
            if(e[i].w&&dep[u]+e[i].c<dep[v]){
                dep[v]=dep[u]+e[i].c;
                if(!inq[v]){
                    que.push(v);
                }
            }
        }
    }
    return dep[T]!=INFLL;
}
ll cost;
int dfs(int u,int inflow){
    if(u==T){
        return inflow;
    }
    vs[u]=true;
    int outflow=0;
    for(int i=arc[u];i;i=e[i].nxt){
        arc[u]=i;
        if(dep[u]+e[i].c!=dep[e[i].v]||!e[i].w||vs[e[i].v]){
            continue;
        }
        int nf=dfs(e[i].v,min(inflow,e[i].w));
        e[i].w-=nf;
        e[i^1].w+=nf;
        cost+=e[i].c*nf;
        outflow+=nf;
        inflow-=nf;
        if(!inflow){
            break;
        }
    }
    vs[u]=false;
    return outflow;
}
int dinic(){
    int ans=0;
    while(spfa()){
        ans+=dfs(S,INF);
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int N;
    cin>>N;
    S=0,T=2*N+1;
    rep(i,1,N){
        int r;
        cin>>r;
        add(i,T,r,0);
        add(S,N+i,r,0);
    }
    int p,m,f,n,s;
    cin>>p>>m>>f>>n>>s;
    rep(i,1,N){
        if(i<N){
            add(N+i,N+i+1,INF,0);
        }
        if(i+m<=N){
            add(N+i,i+m,INF,f);
        }
        if(i+n<=N){
            add(N+i,i+n,INF,s);
        }
        add(S,i,INF,p);
    }
    int flw=dinic();
    cout<<cost<<"\n";
    return 0;
}
posted @ 2026-09-24 14:42  tanghg  阅读(5)  评论(0)    收藏  举报