网络流二十四题之十 —— 餐巾计划问题(NAPK)

来源:互联网 发布:吉林大学网络教学平台 编辑:程序博客网 时间:2024/06/04 13:35

餐巾计划问题


Description

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


Input

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


Output

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


Solution

本题要把握的一点,就是每天生产出来的脏餐巾是固定的——即每天需用的餐斤数。

这样,我们就可以这样构图:
我们将使用餐巾和生产脏餐巾分为两个不同的板块。

因为限制条件为每天需要用一定数目的餐巾,所以在“使用餐巾”这个版块中,我们将每一天都连一条容量为每天需用的餐巾数的边到汇点。

从源点向“生产脏餐巾”的板块提供原料:从源点向每天连一条容量为每天需用的餐巾数的边。

生产出脏餐巾后,连一条容量为无限的边到送往快洗部洗完之后的那一天,费用设置为快洗的费用;连一条容量为无限的边到送往慢洗部洗完之后的那一天,费用设置为慢洗的费用。
另外,可以当天的餐巾不洗,留到第二天或永远不洗,那么我们还需要从每一天向其之后的那一天连一条容量为无限,费用为 0 的边。

最后求最小费用最大流即可。
因为是最大流,所以除了容量为无限的边之外,其它的边均为满流,满足题目条件。


Code

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <queue>  
  5.   
  6. #define Min(x,y) ((x)<(y)?(x):(y))  
  7. #define MAXN 1000010  
  8. #define MAXE 100010  
  9. #define INF 0x3f3f3f3f  
  10. #define ss 0  
  11. #define tt 100005  
  12.   
  13. using namespace std;  
  14.   
  15. int N,p,m,f,n,s,ans;  
  16. int cnt;  
  17. int nxt[MAXN],data[MAXN],wei[MAXN],flow[MAXN],from[MAXN];  
  18. int head[MAXE],dis[MAXE];  
  19. int pre[MAXE];  
  20. bool in_stack[MAXE];  
  21. queue<int>q;  
  22.   
  23. void add(int x,int y,int a,int b){  
  24.     from[cnt]=x;nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=b;flow[cnt]=a;head[x]=cnt++;  
  25.     from[cnt]=y;nxt[cnt]=head[y];data[cnt]=x;wei[cnt]=-b;flow[cnt]=0;head[y]=cnt++;   
  26. }  
  27.   
  28.   
  29. bool BFS(){  
  30.     memset(dis,0x3f,sizeof dis);  
  31.     q.push(ss);dis[ss]=0;in_stack[ss]=true;  
  32.     pre[ss]=pre[tt]=-1;  
  33.     while(!q.empty()){  
  34.         int now=q.front();  
  35.         q.pop();  
  36.         in_stack[now]=false;  
  37.         for(int i=head[now];i!=-1;i=nxt[i]){  
  38.             if(flow[i]&&wei[i]+dis[now]<dis[data[i]]){  
  39.                 dis[data[i]]=wei[i]+dis[now];  
  40.                 pre[data[i]]=(i^1);  
  41.                 if(!in_stack[data[i]]){q.push(data[i]);in_stack[data[i]]=true;}  
  42.             }  
  43.         }  
  44.     }  
  45.     return pre[tt]>0;  
  46. }  
  47.   
  48. void dfs(){  
  49.     int Low=INF;  
  50.     for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);  
  51.     for(int i=pre[tt];i!=-1;i=pre[data[i]]){  
  52.         flow[i^1]-=Low;  
  53.         flow[i]+=Low;  
  54.     }  
  55. }  
  56.   
  57.   
  58. int main(){  
  59.       
  60.     memset(head,-1,sizeof head);  
  61.       
  62.     scanf(”%d%d%d%d%d%d”,&N,&p,&m,&f,&n,&s);  
  63.     for(int i=1;i<=N;i++){  
  64.         int x;  
  65.         scanf(”%d”,&x);  
  66.         add(i+N,tt,x,0);  
  67.         add(ss,i,x,0);  
  68.         if(i+m<=N)add(i,i+N+m,INF,f);  
  69.         if(i+n<=N)add(i,i+N+n,INF,s);  
  70.         if(i!=N)add(i,i+1,INF,0);  
  71.         add(ss,i+N,INF,p);   
  72.     }  
  73.       
  74.     while(BFS())dfs();  
  75.       
  76.           
  77.     for(int i=0;i<cnt;i++){  
  78.         if(from[i]>=1&&from[i]<=N&&data[i]>=N+1&&data[i]!=tt&&data[i]!=ss)ans+=flow[i^1]*wei[i];  
  79.         if(from[i]==ss&&data[i]>=N+1&&data[i]!=tt&&data[i]!=ss)ans+=flow[i^1]*wei[i];  
  80.     }  
  81.     printf(”%d\n”,ans);  
  82.     return 0;  
  83. }  
1 0