【中学高级本-网络流24题】餐巾计划
Description
一个餐厅在相继的N天里,第i天需要Ri块餐巾(i=l,2,…,N)。餐厅可以从三种途径获得餐巾。
(1)购买新的餐巾,每块需p分;
(2)把用过的餐巾送到快洗部,洗一块需m天,费用需f分(f<p)。如m=l时,第一天送到快洗部的餐巾第二天就可以使用了,送慢洗的情况也如此。
(3)把餐巾送到慢洗部,洗一块需n天(n>m),费用需s分(s<f)。
在每天结束时,餐厅必须决定多少块用过的餐巾送到快洗部,多少块送慢洗部。在每天开始时,餐厅必须决定是否购买新餐巾及多少,使洗好的和新购的餐巾之和满足当天的需求量Ri,并使N天总的费用最小。
Input
共 3 行:
第 1 行为总天教;
第 2 行为每天所需的餐巾块数;
第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。
Output
一行,最小的费用
Sample Input
3
3 2 4
10 1 6 2 3
Sample Output
64
Hint
数据规模:
n<=200,Ri<=50
Source
网络流
线性规划网络优化,最小费用最大流
解析
这题也就是建图。。。
首先,我们要考虑拆点,
将一天拆成早上和晚上,
那么,每天早上,餐厅都会得到到干净的餐巾,
而餐巾则来自于购买,或是kt,mt天前的晚上(因为洗完了)(本题解中,kt为快洗天数,mt为慢洗天数,kp为快洗价格,mp为慢洗价格)。
而每天晚上,餐厅都将有X张旧餐巾产生,
而这些餐巾将会被快洗,慢洗,扔掉或是留到后一天晚上(第一次交的时候没考虑这种情况然后WA了)。
那么,我们就可以开始建图了!
首先,将源点与每天晚上连起来,流量为当天需要的餐巾数,费用为零,表示当天晚上收到的旧餐巾。
接下来,将每天晚上与kt,mt天后的早上连起来(大于n要特判),
流量为INF,费用为kp,mp,
表示洗完后的早上能得到洗的餐巾。
再将每天晚上与后一天晚上连起来,流量为INF,费用为零,表示将当天的旧餐巾放到第二天晚上再处理。
最后,将每天早上与汇点连起来,流量为当天的餐巾数,费用为零,表示当天早上收到的餐巾。
再跑最小费用最大流就行了!
上AC代码:
#include<bits/stdc++.h> #define ll long long using namespace std; inline ll read(){ ll sum=0,f=1;char ch=getchar(); while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();} return f*sum; } const int INF=10000000000000; struct node{ int next,to; ll v,w; }e[1000001]; struct hh{ int fa,edge; }pre[100001]; int n,m,s,t,a[100001]; int p,kp,kt,mp,mt; int head[100001],cnt=1; int inq[100001]; ll d[100001],mi[100001]; void add(int x,int y,int v,int w){ e[++cnt].to=head[x]; e[cnt].next=y; e[cnt].w=w; e[cnt].v=v; head[x]=cnt; } bool spfa(){ memset(pre,0,sizeof(pre)); for(int i=1;i<=n*2+3;i++) d[i]=INF; for(int i=1;i<=n*2+3;i++) mi[i]=INF; memset(inq,0,sizeof(inq)); queue <int> que; que.push(s); d[s]=0; while(!que.empty()){ int x=que.front(); inq[x]=0; que.pop(); for(int i=head[x];i;i=e[i].to){ int k=e[i].next; if(d[k]>d[x]+e[i].w&&e[i].v){ d[k]=d[x]+e[i].w; pre[k].fa=x; pre[k].edge=i; mi[k]=min(mi[x],e[i].v); if(!inq[k]) que.push(k); inq[k]=1; } } } return d[t]!=INF; } void EK(){ ll cost=0,ret; while(spfa()){ ret=mi[t]; for(int i=t;i!=s;i=pre[i].fa){ e[pre[i].edge].v-=ret; e[pre[i].edge^1].v+=ret; } cost+=ret*d[t]; } printf("%lld\n",cost); return ; } int main(){ n=read(); s=n*2+1;t=n*2+2; for(int i=1;i<=n;i++){ a[i]=read(); } p=read();kt=read();kp=read();mt=read();mp=read(); for(int i=1;i<=n;i++){ add(s,i,INF,p); add(i,s,0,-p); add(s,i+n,a[i],0); add(i+n,s,0,0); if(i+kt<=n){ add(i+n,i+kt,INF,kp); add(i+kt,i+n,0,-kp); } if(i+mt<=n){ add(i+n,i+mt,INF,mp); add(i+mt,i+n,0,-mp); } add(i,t,a[i],0); add(t,i,0,0); if(i<n){ add(i+n,i+1+n,INF,0); add(i+1+n,i+n,0,0); } } EK(); return 0; }