【网络流24题】餐巾计划(最小费用流)

本文探讨了餐巾计划问题,通过引入最小费用最大流的概念来解决。文章设置了源汇点S和T,并对每天的餐巾需求进行建模。利用SPFA算法寻找最小费用的增广路径,以实现成本最低的餐巾分配方案。
摘要由CSDN通过智能技术生成

传送门

    餐巾计划

I think

    最小费用最大流。增设源汇点S,T,每i天分两个点xi,yi,分别表示每天应有餐巾与最终解决的餐巾数。记 (x,y,u,v) 表示x连向y点容量为u费用为v点的边,连接以下边 (S,xi,ai,0),(yi,T,ai,0),(xi,xi+1,Inf,0),(xi,yi+qk,Inf,qc),(xi,yi+lk,Inf,lc); 最后用SPFA+增广路思想求出最小费用即可。
    另算法函数名很无赖地用了SPFA。

Code

#include<cstdio>
#include<queue>
using namespace std;

const int sm = 2200;
const int sn = 12200;
const int Inf = 0x3f3f3f3f;

int N,nw,qk,qc,lw,lc,Ans,tot=1,S,T;
int to[sn],nxt[sn],hd[sm],c[sn],f[sn];
int pre[sm],vis[sm],cst[sm];

int Min(int x,int y) { return x<y?x:y; }

void Add(int u,int v,int w,int val) {
    to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=w,f[tot]=val;
    to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0,f[tot]=-val;
}

void SPFA() {
    int t,df; queue<int>q;
    while(1) {
        for(int i=1;i<=T;++i) 
            pre[i]=vis[i]=0,cst[i]=Inf;
        cst[S]=0,vis[S]=1,q.push(S);
        while(!q.empty()) {
            t=q.front(),q.pop();
            vis[t]=0;
            for(int i=hd[t];i;i=nxt[i])
                if(cst[to[i]]>cst[t]+f[i]&&c[i]>0) {
                    cst[to[i]]=cst[t]+f[i];
                    pre[to[i]]=i;
                    if(!vis[to[i]]) {
                        vis[to[i]]=1;
                        q.push(to[i]);
                    }
                }
        }
        if(cst[T]==Inf)break;
        df=Inf;
        for(int i=T;i!=S;i=to[pre[i]^1]) 
            df=Min(df,c[pre[i]]);
        for(int i=T;i!=S;i=to[pre[i]^1]) 
            c[pre[i]]-=df,c[pre[i]^1]+=df;
        Ans+=df*cst[T];
    }
    printf("%d\n",Ans); 
}

int main() {
    int u;
    scanf("%d%d%d%d%d%d",&N,&nw,&qk,&qc,&lw,&lc);
    S=N<<1|1,T=S+1;
    for(int i=1;i<=N;++i) {
        scanf("%d",&u);
        Add(S,i,u,0),Add(i+N,T,u,0);
        Add(S,i+N,Inf,nw);
        if(i+1<=N) Add(i,i+1,Inf,0);
        if(i+qk<=N) Add(i,i+N+qk,Inf,qc);
        if(i+lw<=N) Add(i,i+N+lw,Inf,lc);
    }
    SPFA();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值