• [网络流24题] 10.餐巾计划问题 解题报告 (最小费用最大流)


    10.餐巾计划问题

    题意

    一间餐厅需要连续运营 (N) 天, 每天都有不同的餐巾需求量 (r[i]),

    每天可以有 4 种操作,

    1. 购买新的餐巾, 每条餐巾的费用为 (p).
    2. 将用过的餐巾保存, 留到下一天.
    3. 将用过的餐巾送到快洗部, (m) 天后拿到餐巾, 每条餐巾的清洗费用为 (f).
    4. 将用过的餐巾送到慢洗部, (n) 天后拿到餐巾, 每条餐巾的清洗费用为 (s).

    求满足每天餐巾需求的总费用最小值.


    思路

    每天都需要有 (r[i]) 条餐巾, 那么考虑从节点 (i)(T) 连一条容量为 (r[i]) 的边, 那我们的大致思路就确定为了 最小费用最大流.

    再考虑每天需要的餐巾可以从哪里获得,

    1. 新购买.
    2. (i-m) 花费 $f/ $条 的代价获得.
    3. (i-n) 花费 (s/)条 的代价获得.

    那我们再考虑把每一天拆成 供给点需求点, 也可以理解为这一天的 结束开始.

    (i) 天的供给点为 (i), 需求点为 (i+).N

    每个供给点 (i) 就需要往外连三条边, 分别对应题意中的后三种操作,

    1. 连向 (i+1), 容量为 (inf), 边权为 (0), 表示把用过的毛巾留到下一天.
    2. 连向 (i+m+N), 容量为 (inf), 边权为 (f), 表示把用过的毛巾送到快洗部.
    3. 连向 (i+n+N), 容量为 (inf), 边权为 (s), 表示把用过的毛巾送到慢洗部.

    除此之外, 我们还需要新建一个供给点, 向所有需求点连容量为 (inf) ,边权为 (p) 的边, 表示当天新购买的毛巾.

    图建完后, 跑个费用流即可. (费用流 -- OI Wiki)


    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int _=1e5+7;
    const int __=1e7+7;
    const ll inf=1e17;
    int n,p,fd,fc,sd,sc;  // fd,fc,sd,sc 分别对应题目中的 m,f,n,s
    int S,T,apl,lst[_],nxt[__],to[__],tot=1;
    ll dis[_],w[__],c[__],ans;
    bool vis[_];
    queue<int> q;
    void add(int x,int y,ll cap,ll wgt){
      nxt[++tot]=lst[x]; to[tot]=y; c[tot]=cap; w[tot]=wgt; lst[x]=tot;
      nxt[++tot]=lst[y]; to[tot]=x; c[tot]=0; w[tot]=-wgt; lst[y]=tot;
    }
    void init(){
      cin>>n; int nd;
      S=2*n+1,T=2*n+2,apl=2*n+3;
      for(int i=1;i<=n;i++){
        scanf("%d",&nd);
        add(S,i,(ll)nd,0);
        add(i+n,T,(ll)nd,0);
        add(apl,i+n,inf,0);
      }
      scanf("%d%d%d%d%d",&p,&fd,&fc,&sd,&sc);
      add(S,apl,inf,p);
      for(int i=1;i<=n;i++){
        if(i<n) add(i,i+1,inf,0);
        if(i+fd<=n) add(i,i+fd+n,inf,fc);
        if(i+sd<=n) add(i,i+sd+n,inf,sc);
      }
    }
    bool bfs(){
      for(int i=1;i<=apl;i++) dis[i]=inf;
      memset(vis,0,sizeof(vis));
      while(!q.empty()) q.pop();
      dis[S]=0; q.push(S);
      while(!q.empty()){
        int u=q.front(); q.pop();
        vis[u]=0;
        for(int i=lst[u];i;i=nxt[i]){
          int v=to[i];
          if(dis[v]<=dis[u]+w[i]||!c[i]) continue;
          dis[v]=dis[u]+w[i];
          if(!vis[v]){
    	q.push(v);
    	vis[v]=1;
          }
        }
      }
      return dis[T]!=inf;
    }
    ll dfs(int u,ll flow){
      if(u==T) return flow;
      ll rest=flow; vis[u]=1;
      for(int i=lst[u];i;i=nxt[i]){
        int v=to[i];
        if(vis[v]||dis[v]!=dis[u]+w[i]||!c[i]) continue;
        ll cst=dfs(v,min(rest,c[i]));
        if(cst==0) dis[v]=-inf;
        else{
          c[i]-=cst; c[i^1]+=cst;
          rest-=cst; ans+=cst*w[i];
        }
      }
      vis[u]=0;
      return flow-rest;
    }
    void Dinic(){
      ll flow;
      while(bfs()){
        do{
          flow=dfs(S,inf);
        }while(flow);
      }
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      init();
      Dinic();
      printf("%lld
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    SQL查询语句中,any和all有什么区别?
    $(function(){...});
    在ASP.NET中TextBox和TextBoxFor的区别以及ValidationMessageFor的作用以及EditorFor等的作用和用法什么?
    Brt课程设计day3
    Brt课程设计day2
    day1
    .net 高级写法总结
    可能是目前最完整的前端框架 Vue.js 全面介绍
    redis live 如何安装
    百万级PHP网站架构工具箱
  • 原文地址:https://www.cnblogs.com/BruceW/p/12204579.html
Copyright © 2020-2023  润新知