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

CGOS461 [网络流24题] 餐巾(最小费用最大流)

2016-04-07 18:48 357 查看
题目这么说的:


一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。

购买新的餐巾,每块需p分;

把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。

把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。

在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。


挺有趣的题,至少还需要稍微思考思考。。考虑用最小费用最大流。

首先显然要把各天作为点向汇点连容量为当天所需餐巾个数且费用为0的边,这样的最大流就满足各天供应的需求的条件;

然后对于购买餐巾,源点向各天连容量为INF费用p的边;

而最后还需要建洗餐巾重复利用餐巾的边,这么考虑:

对于第i天都会有Ri个餐巾可以重复利用,而第j天(j>=i+m)则可以得到快洗的第i天的餐巾,单位费用为f,慢洗的同理;

这样就清楚了:再新建n个顶点,源点向第i个新点连容量Ri费用0的边,第i个新点向第j天(j>=i+m)的点连容量INF费用f的边,第i个新点向第k天(k>=i+n)的点连容量INF费用s的边。

这样建完图跑最小费用最大流就OK了。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 444
#define MAXM 444*888
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int head[MAXN];
int NV,NE,vs,vt;

void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
bool vis[MAXN];
int d[MAXN],pre[MAXN];
bool SPFA(){
for(int i=0;i<NV;++i){
vis[i]=0;
d[i]=INF;
}
vis[vs]=1;
d[vs]=0;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
que.push(v);
}
}
}
vis[u]=0;
}
return d[vt]!=INF;
}
int MCMF(){
int res=0;
while(SPFA()){
int flow=INF,cost=0;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^1].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int need[222];
int main(){
freopen("napkin.in","r",stdin);
freopen("napkin.out","w",stdout);
int n,p,a,b,x,y;
scanf("%d",&n);
for(int i=1; i<=n; ++i){
scanf("%d",need+i);
}
scanf("%d%d%d%d%d",&p,&a,&b,&x,&y);
vs=0; vt=n*2+1; NV=vt+1; NE=0;
memset(head,-1,sizeof(head));
for(int i=1; i<=n; ++i){
addEdge(vs,i+n,INF,p);
addEdge(i+n,vt,need[i],0);
addEdge(vs,i,need[i],0);
for(int j=i+a; j<=n; ++j) addEdge(i,j+n,INF,b);
for(int j=i+x; j<=n; ++j) addEdge(i,j+n,INF,y);
}
printf("%d",MCMF());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: