网络流24题 P1251 餐巾计划问题 拆点

  

题目描述

一个餐厅在相继的 NN 天里,每天需用的餐巾数不尽相同。假设第 ii 天需要 r_iri块餐巾( i=1,2,...,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 pp 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 nn 天(n>mn>m),其费用为 ss 分(s<fs<f)。

每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。

试设计一个算法为餐厅合理地安排好 NN 天中餐巾使用计划,使总的花费最小。编程找出一个最佳餐巾使用计划。

我们知道,对于每一天,其实有两种状态:

    一天开始状态,这个时候应该决定买多少新的餐巾数目,有没有从洗衣部送过来的东西

    第一天结束,我们需要决定,是否需要对用过的餐巾进行封存,是否需要对把衣服送到两种洗衣部里面

那么很明显,一个点不能满足我们的需求,我们可以把点进行拆分,分成白天和晚上,对应有6种情况

  我们需要从起点连接每个白天,流量限制,费用为p,代表这个的餐巾选择新购买的数目

   从起点再连接每个点的晚上,流量限制为这一天所需的餐巾数目,代表这一天一定会产生这么多的用过的餐巾

   从每天早上连接到汇点流量限制为这一天所需的餐巾数目,代表这白天一定会消耗这么多餐巾

   由于可以把用过的餐巾存起来,我们把每个晚上的餐巾存到第二天从餐巾,流量为今天用的餐巾数目,费用为0

   我们可以把餐巾送到快洗部,那么应该这天晚上的餐巾,送到洗完的那一天的早上,流量上限是INF(因为可能有以前存的衣服),费用为快洗部的费用

  也可以把餐巾送到慢洗部,那么应该这天晚上的餐巾,送到洗完的那一天的早上,流量上限是INF(因为可能有以前存的衣服),费用为慢洗部的费用

  注意拆点的话,可以把点拆成i和i+n  

代码:

   

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<queue>
#define LL long long
using namespace std;
const LL N = 3e4+4,M = 4e6+7;
const LL INF = 0x3f3f3f3f;
LL ver[M],edge[M],cost[M],Next[M],head[N];
LL d[N],incf[N],pre[N],v[N],a[N];
LL n,k,tot,s,t,maxflow;
LL ans;
void add(LL x,LL y,LL z,LL c){
  ver[++tot]=y,edge[tot]=z,cost[tot]=c;
  Next[tot]=head[x],head[x]=tot;

  ver[++tot]=x,edge[tot]=0,cost[tot]=-c;
  Next[tot]=head[y],head[y]=tot;
}
bool spfa(){
   queue<LL>q;
   for (LL i=0;i<=N;i++){
    d[i]=INF;
   }
   memset(v,0,sizeof(v));
   q.push(s);
   d[s]=0;
   v[s]=1;
   incf[s]=INF;
   while(q.size()){
      LL x=q.front();
      v[x]=0;
      q.pop();
      for (int i=head[x];i;i=Next[i]){
         if(!edge[i])
            continue;
         int y=ver[i];
         if (d[y]>d[x]+cost[i] && edge[i]>0){
            d[y]=d[x]+cost[i];
            incf[y]=min(incf[x],edge[i]);
            pre[y]=i;
            if (!v[y])v[y]=1,q.push(y);
         }
      }
   }
   if (d[t]==INF)return false;
   return true;
}
void update(){
   int x=t;
   while(x!=s){
      int i=pre[x];
      edge[i]-=incf[t];
      edge[i^1]+=incf[t];
      x=ver[i^1];
   }
   maxflow+=incf[t];
   ans+=d[t]*incf[t];
}
int main(){
  LL q_day,q_w,s_day,s_w,p,
  maxflow=0;
  ans=0;
  tot=1;
  scanf("%lld",&n);
  s=2*n+2;
  t=2*n+3;
  for (LL i=1;i<=n;i++){
    scanf("%lld",&a[i]);
  }
  scanf("%lld%lld%lld%lld%lld",&p,&q_day,&q_w,&s_day,&s_w);
  for (LL i=1;i<=n;i++){
    add(s,i,INF,p);
    add(s,i+n,a[i],0);
    add(i,t,a[i],0);
    if (i<n)add(i+n,i+n+1,INF,0);
    if (i+q_day<=n){
        add(i+n,i+q_day,INF,q_w);
    }
    if (i+s_day<=n){
        add(i+n,i+s_day,INF,s_w);
    }
  }
  while(spfa())update();
  printf("%lld\n",ans);
  return 0;
}

 

全部评论

相关推荐

行云流水1971:这份实习简历的优化建议: 结构清晰化:拆分 “校园经历”“实习经历” 板块(当前内容混杂),按 “实习→校园→技能” 逻辑排版,求职意向明确为具体岗位(如 “市场 / 运营实习生”)。 经历具象化:现有描述偏流程,需补充 “动作 + 数据”,比如校园活动 “负责宣传” 可加 “运营公众号发布 5 篇推文,阅读量超 2000+,带动 300 + 人参与”;实习内容补充 “协助完成 XX 任务,效率提升 X%”。 岗位匹配度:锚定目标岗位能力,比如申请运营岗,突出 “内容编辑、活动执行” 相关动作;申请市场岗,强化 “资源对接、数据统计” 细节。 信息精简:删减冗余表述(如重复的 “负责”),用短句分点,比如 “策划校园招聘会:联系 10 + 企业,组织 200 + 学生参与,到场率达 85%”。 技能落地:将 “Office、PS” 绑定经历,比如 “用 Excel 整理活动数据,输出 3 份分析表;用 PS 设计 2 张活动海报”,避免技能单独罗列。 优化后需强化 “经历 - 能力 - 岗位需求” 的关联,让实习 / 校园经历的价值更直观。 若需要进一步优化服务,私信
实习,投递多份简历没人回...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务