1. 程式人生 > >「網路流 24 題」餐巾計劃 費用流 新流新用vs舊流新用

「網路流 24 題」餐巾計劃 費用流 新流新用vs舊流新用

        中文的題面,所以我就不解釋了,之前做了一道飛行員的題目和這道幾乎是一個意思。我就自作主張的起了“新流新用vs舊流新用”這個標題,為什麼呢,解釋一下這道題的建圖。

        這個題把每一天的餐巾情況進行了拆點,點i代表的是這天因為用過了之後留下來要洗的餐巾,點i’代表的是當天可用的乾淨餐巾的數量。

        假設我們不考慮有舊流補入的情況(不考慮可以洗餐巾的情況)

        先將源點到1'(我的程式碼中是2),連一條容量為inf費用為P的邊,代表可以用P一條的價格買入新的餐巾。

        將i'->i+1'連容量為inf費用為0的邊,代表當天如果有沒用用完的乾淨的餐巾,那麼可以留到下一天(每天都要買新餐巾的情況直接用源點到1'代表了,因為如果後面要買的話,直接從前面把流擴大就好(即第一天會買好所有需要的),就不用每天都從源點連邊啦)。

        將i'向匯點連一條流量為need[i],費用為0的邊,表示每天都要提供這麼多餐巾,直接把這些流給收掉。

        然後我們再考慮有舊流補入的情況,那麼我們就要用到點i了;

        因為每天都會有need[i]那麼多的舊餐巾產生,所以直接從源點向點i連邊,費用為0。

        重點來了!然後就是要連邊i->i+M,容量為inf,費用為F,i->i+N,容量為inf,費用為S。為什麼呢,因為從第i天可以直接向i+M天通過洗滌得到乾淨的餐巾,即這些流可以直接變為新的流再往下跑。為什麼是inf呢,其實只要大於need[i]就好了,因為在源點連邊的時候就已經限制了流量。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=6000;
const int maxm=600000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt;
int n,m,sp,tp;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
int mcmf(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return cost;
}
int need[maxn];
int gainp(int x,int y){
    return (x-1)*2+y;
}
int main(){
    int P,M,F,N,S;
    memset(head,-1,sizeof(head));

    scanf("%d%d%d%d%d%d",&n,&P,&M,&F,&N,&S);
    cnt=0,sp=0,tp=2*n+1;
    for(int i=1;i<=n;i++)
        scanf("%d",&need[i]);
    add(sp,2,inf,P);
    for(int i=1;i<=n;i++){
        add(sp,gainp(i,1),need[i],0);
        add(gainp(i,2),tp,need[i],0);
        if(i!=n) add(gainp(i,2),gainp(i+1,2),inf,0);
        if(i+M<=n)add(gainp(i,1),gainp(i+M,2),inf,F);
        if(i+N<=n) add(gainp(i,1),gainp(i+N,2),inf,S);
    }
    printf("%d\n",mcmf(sp,tp));
    return 0;
}