「网络流24题」「Codevs1237」 餐巾计划问题

1237 餐巾计划问题

 

时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
 
题目描述 Description

一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。假设第 i 天需要 ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。
编程找出一个最佳餐巾使用计划.

输入描述 Input Description

第 1 行有 6 个正整数 N,p,m,f,n,s。N 是要安排餐巾使用计划的天数;p 是每块新餐巾的费用;m 是快洗部洗一块餐巾需用天数;f 是快洗部洗一块餐巾需要的费用;n 是慢洗部洗一块餐巾需用天数;s 是慢洗部洗一块餐巾需要的费用。接下来的 N 行是餐厅在相继的 N 天里,每天需用的餐巾数。

输出描述 Output Description

将餐厅在相继的 N 天里使用餐巾的最小总花费输出

样例输入 Sample Input

3 10 2 3 3 2

5

6

7

样例输出 Sample Output

145

数据范围及提示 Data Size & Hint

N<=2000

ri<=10000000

p,f,s<=10000

时限4s

题解

最小费用最大流。

把每天拆成两个点,脏毛巾(1~N)和干净毛巾(N+1~2N),

 

从源点往每个干净毛巾的点连一条费用为p,流量INF的边;(买新毛巾

每个干净点往汇点连费用为0,流量ri的边(提供干净毛巾

从源点往每个脏毛巾点连费用为0,流量ri的边(给处理的人脏毛巾

每个脏点往m天后的干净点连费用为f,流量INF的边(让快洗部洗

同理往n天后的干净点连费用为s,流量INF的边(让慢洗部洗

以及,每个脏点往下一个脏点连费用为0,流量INF(留着不洗

 

最后跑一遍从S到T的费用流,输出最小费用。

  1 #include<queue>
  2 #include<cmath>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<iostream>
  6 using namespace std;
  7 const int INF=999999999;
  8 int n,fx,tk,fk,tm,fm;
  9 int s,t;
 10 struct emm{
 11     int e,f,v,c;
 12 }a[300007];
 13 int h[2007];
 14 int tot=1;
 15 void con(int l,int r,int vv,int cc)
 16 {
 17     a[++tot].f=h[l];
 18     h[l]=tot;
 19     a[tot].e=r;
 20     a[tot].v=vv;
 21     a[tot].c=cc;
 22     a[++tot].f=h[r];
 23     h[r]=tot;
 24     a[tot].e=l;
 25     a[tot].c=-cc;
 26     return;
 27 }
 28 int d[2007];
 29 bool sf[2007];
 30 queue<int>q;
 31 inline bool spfa()
 32 {
 33     memset(sf,0,sizeof(sf));
 34     memset(d,127,sizeof(d));
 35     d[s]=0;sf[s]=1;q.push(s);
 36     while(!q.empty())
 37     {
 38         int x=q.front();q.pop();
 39         for(int i=h[x];i;i=a[i].f)
 40         if(d[x]+a[i].c<d[a[i].e]&&a[i].v)
 41         {
 42             d[a[i].e]=d[x]+a[i].c;
 43             if(!sf[a[i].e])
 44             {
 45                 sf[a[i].e]=1;
 46                 q.push(a[i].e);
 47             }
 48         }
 49         sf[x]=0;
 50     }
 51     return d[t]<INF;
 52 }
 53 unsigned long long ans=0;
 54 int dfs(int x,int al)
 55 {
 56     sf[x]=1;
 57     if(x==t||!al)return al;
 58     int fl=0;
 59     for(int i=h[x];i;i=a[i].f)
 60     if(d[a[i].e]==d[x]+a[i].c&&a[i].v&&!sf[a[i].e])
 61     {
 62         int f=dfs(a[i].e,min(al,a[i].v));
 63         if(f)
 64         {
 65             fl+=f;
 66             al-=f;
 67             ans+=f*a[i].c;
 68             a[i].v-=f;
 69             a[i^1].v+=f;
 70             if(!al)break;
 71         }
 72     }
 73     if(!fl)d[x]=-INF;
 74     return fl;
 75 }
 76 void scan()
 77 {
 78     scanf("%d%d%d%d%d%d",&n,&fx,&tk,&fk,&tm,&fm);
 79     s=0,t=2*n+1;
 80     for(int i=1;i<=n;++i)
 81     {
 82         int ri;
 83         scanf("%d",&ri);
 84         con(s,i,ri,0);
 85         con(s,i+n,INF,fx);
 86         con(i+n,t,ri,0);
 87         if(i<n)con(i,i+1,INF,0);
 88         if(i+tm<=n)con(i,i+tm+n,INF,fm);
 89         if(i+tk<=n)con(i,i+tk+n,INF,fk);
 90     }
 91     return;
 92 }
 93 void zkw()
 94 {
 95     while(spfa())
 96     {
 97         sf[t]=1;
 98         while(sf[t])
 99         {
100             memset(sf,0,sizeof(sf));
101             dfs(s,INF);
102         }
103     }
104     return;
105 }
106 int main()
107 {
108     scan();
109     zkw();
110     cout<<ans;
111     return 0;
112 }

 

转载于:https://www.cnblogs.com/qwerta/p/9613781.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值