[学习笔记]费用流 - 餐巾计划

屯板子,以餐巾计划问题为例。
根据上下界网络流的一般做法,可以得知这里如果minf=0那么就是一般的网络流的边。
否则

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<queue>
#define N 4020
#define M 15*N
#define P(x) x
#define Q(x) (x+n)
#define inf INT_MAX
#define INF LLONG_MAX
#define lint long long
using namespace std;
struct edges{
    int from,to,pre,resf,cost;
}e[M];int etop,h[N];
inline int add_edge(int u,int v,int f,int c)
{
    e[++etop].from=u,e[etop].to=v,e[etop].pre=h[u];
    return e[etop].resf=f,e[etop].cost=c,h[u]=etop;
}
inline int build_edge(int u,int v,int f,int c)
{
    return add_edge(u,v,f,c),add_edge(v,u,0,-c);
}
lint d[N];bool inq[N];int fr[N];queue<int> q;
inline int spfa(int s,int t,int &flow,lint &cost)
{
    for(int i=1;i<=t;i++) d[i]=INF;
    memset(inq,false,sizeof(inq));
    memset(fr,0,sizeof(fr));
    while(!q.empty()) q.pop();
    q.push(s),inq[s]=true,d[s]=0;
    while(!q.empty())
    {
        int x=q.front();q.pop(),inq[x]=false;
        for(int i=h[x],y;i;i=e[i].pre)
            if(e[i].resf&&d[y=e[i].to]>d[x]+e[i].cost)
            {
                d[y]=d[x]+e[i].cost,fr[y]=i;
                if(!inq[y]) inq[y]=true,q.push(y);
            }
    }
    if(!fr[t]) return false;int minf=inf;
    for(int i=fr[t];i;i=fr[e[i].from])
        minf=min(minf,e[i].resf);
    for(int i=fr[t];i;i=fr[e[i].from])
        e[i].resf-=minf,e[((i-1)^1)+1].resf+=minf;
    cost+=d[t]*minf,flow+=minf;return true;
}
int main()
{
    int n;scanf("%d",&n);
    int s=2*n+1,t=s+1;
//  build_edge(t,s,inf,0);
    for(int i=1;i<=n;i++)
    {
        int r;scanf("%d",&r);
        build_edge(s,Q(i),r,0);
        build_edge(P(i),t,r,0);
    }
    int p,x,y,a,b;
    scanf("%d%d%d%d%d",&p,&x,&a,&y,&b);
    for(int i=1;i<=n;i++)
    {
        build_edge(s,P(i),inf,p);
        if(i+x<=n) build_edge(Q(i),P(i+x),inf,a);
        if(i+y<=n) build_edge(Q(i),P(i+y),inf,b);
    }
    for(int i=1;i<n;i++) build_edge(P(i),P(i+1),inf,0);
    int f=0;lint c=0;
    while(spfa(s,t,f,c));
    cout<<c<<endl;return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值