P2517 [HAOI2010]订货

简要题意

一家公司销售一种商品,在时刻 (i) 可以需要 (U_i) 份商品。第 (i) 时刻向生产方购买 (1) 份商品需要 (d_i) 的代价。(i-1) 时刻的 (1) 份商品滞留到 (i) 时刻,需要花费 (m) 的代价,且一共只能滞留 (S) 份商品。

问经营 (n) 个时刻的最小花费。

(0\leq n\leq 50, 0\leq m \leq 10, 0\leq S\leq 10000,0 \leq U_i \leq 10000,0 \leq d_i \leq 100)

对于 (i) 时刻,建立点 (i),然后考虑连边:

  • 对于滞留商品,我们连边((i-1,i,S,m))(这一点显然易见)。
  • 对于需要商品,我们像餐厅计划问题一样,建立超级汇点(T),然后连边((i,T,U_i,0))。
  • 对于购买商品,我们像餐厅计划问题一样,建立超级源点(S),然后连边((S,i,+\infty,d_i))。

这里再解释一下连边:需要商品时,不能从上一个节点连边,因为剩余不方便计算。但是我们如果连向汇点,那么就直接限制了流量,也就是说,如果要有流量,那么必须要有 (U_i) 的流量。购买商品时,没有商品份数限制,因此流量为 (+\infty),买一份需要 (d_i),所以费用时 (d_i)。总之,这里流量时商品个数,费用时花费。

然后直接跑 (S) 为源 (T) 为汇的最小费用最大流即可。时间复杂度 (O(\operatorname{mcmf}(n,n)))。

#include
#define int long long
using namespace std;

int n,m,s;

namespace MCMF{
    struct edge{
        int nxt,to,cap,cost;
    } g[100005];
    int head[100005],ec=-1;
    void add(int from,int to,int cap,int cost){
        g[++ec].nxt=head[from];
        g[ec].to=to;
        g[ec].cap=cap;
        g[ec].cost=cost;
        head[from]=ec;
    }
    void add_edge(int from,int to,int cap,int cost){
        add(from,to,cap,cost);
        add(to,from,0,-cost);
    }
    queue q;
    bool vis[100005];
    int flow[100005];
    int dis[100005];
    int pre[100005];
    int last[100005];
    bool spfa(int s,int t){
        memset(dis,0x7f,sizeof(dis));
        memset(flow,0x7f,sizeof(flow));
        memset(vis,0,sizeof(vis));
        q.push(s);
        vis[s]=1;
        dis[s]=0;
        pre[t]=-1;
        while(!q.empty()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i!=-1;i=g[i].nxt){
                int v=g[i].to;
                if(g[i].cap>0 && dis[v]>dis[u]+g[i].cost){
                    dis[v]=dis[u]+g[i].cost;
                    pre[v]=u;
                    last[v]=i;
                    flow[v]=min(flow[u],g[i].cap);
                    if(!vis[v]){
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return pre[t]!=-1;
    }

    pair MCMF(int s,int t){
        int maxflow=0,mincost=0;
        while(spfa(s,t)){
            int now=t;
            maxflow+=flow[t];
            mincost+=flow[t]*dis[t];
            while(now!=s){
                g[last[now]].cap-=flow[t];
                g[last[now]^1].cap+=flow[t];
                now=pre[now];
            }
        }
        return make_pair(maxflow,mincost);
    }
}

int S,T;

signed main(){
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    memset(MCMF::head,-1,sizeof(MCMF::head));
    MCMF::ec=-1;
    cin>>n>>m>>s;
    S=0,T=n+1;
    for(int i=1,u;i>u;
        MCMF::add_edge(i,T,u,0);
    }
    for(int i=1,d;i>d;
        MCMF::add_edge(S,i,LLONG_MAX,d);
    }
    for(int i=2;i

Original: https://www.cnblogs.com/zheyuanxie/p/p2517.html
Author: xiezheyuan
Title: P2517 [HAOI2010]订货

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/604581/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球