您的位置:首页 > 理论基础 > 计算机网络

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

2016-05-16 21:32 351 查看

餐巾计划问题

Description

一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。

假设第 i 天需要 ri 块餐巾 (i=1,2,…,N)。

餐厅可以购买新的餐巾,每块餐巾的费用为 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]#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

#define Min(x,y) ((x)<(y)?(x):(y))
#define MAXN 1000010
#define MAXE 100010
#define INF 0x3f3f3f3f
#define ss 0
#define tt 100005

using namespace std;

int N,p,m,f,n,s,ans;
int cnt;
int nxt[MAXN],data[MAXN],wei[MAXN],flow[MAXN],from[MAXN];
int head[MAXE],dis[MAXE];
int pre[MAXE];
bool in_stack[MAXE];
queue<int>q;

void add(int x,int y,int a,int b){
from[cnt]=x;nxt[cnt]=head[x];data[cnt]=y;wei[cnt]=b;flow[cnt]=a;head[x]=cnt++;
from[cnt]=y;nxt[cnt]=head[y];data[cnt]=x;wei[cnt]=-b;flow[cnt]=0;head[y]=cnt++;
}

bool BFS(){
memset(dis,0x3f,sizeof dis);
q.push(ss);dis[ss]=0;in_stack[ss]=true;
pre[ss]=pre[tt]=-1;
while(!q.empty()){
int now=q.front();
q.pop();
in_stack[now]=false;
for(int i=head[now];i!=-1;i=nxt[i]){
if(flow[i]&&wei[i]+dis[now]<dis[data[i]]){
dis[data[i]]=wei[i]+dis[now];
pre[data[i]]=(i^1);
if(!in_stack[data[i]]){q.push(data[i]);in_stack[data[i]]=true;}
}
}
}
return pre[tt]>0;
}

void dfs(){
int Low=INF;
for(int i=pre[tt];i!=-1;i=pre[data[i]])Low=Min(Low,flow[i^1]);
for(int i=pre[tt];i!=-1;i=pre[data[i]]){
flow[i^1]-=Low;
flow[i]+=Low;
}
}

int main(){

memset(head,-1,sizeof head);

scanf(”%d%d%d%d%d%d”,&N,&p,&m,&f,&n,&s);
for(int i=1;i<=N;i++){
int x;
scanf(”%d”,&x);
add(i+N,tt,x,0);
add(ss,i,x,0);
if(i+m<=N)add(i,i+N+m,INF,f);
if(i+n<=N)add(i,i+N+n,INF,s);
if(i!=N)add(i,i+1,INF,0);
add(ss,i+N,INF,p);
}

while(BFS())dfs();

for(int i=0;i<cnt;i++){
if(from[i]>=1&&from[i]<=N&&data[i]>=N+1&&data[i]!=tt&&data[i]!=ss)ans+=flow[i^1]*wei[i];
if(from[i]==ss&&data[i]>=N+1&&data[i]!=tt&&data[i]!=ss)ans+=flow[i^1]*wei[i];
}
printf(”%d\n”,ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: