[网络流24题]餐巾计划问题
题目:洛谷P1251。
题目大意:
一个餐厅N天,每天需要ri块餐巾。每块餐巾需要p元,每天用过的餐巾变脏,不能直接用。现在有快洗店和慢洗店,快洗店洗餐巾需要m天,每块花费f元;慢洗店洗餐巾需要n天,每块餐巾s元(m < n,s< f)。现要求最新的花费使满足每天所需。
解题思路:
最小费用最大流建模。
把每天拆成白天和晚上(白天产生脏餐巾,晚上得到干净餐巾)。
从S向每个白天连容量ri,费用0的边;从每个晚上向T连容量ri,费用0的边。代表每天所需的餐巾数。
从第i天的白天向第i+m天的晚上连容量无穷,费用f的边。(快洗)
从第i天的白天向第i+n天的晚上连容量无穷,费用s的边。(慢洗)
从S向每天晚上连容量无穷,费用p的边,代表直接买干净的餐巾。
从第i天晚上向第i+1天晚上连容量无穷,费用0的边,代表干净餐巾可以留到下一天。
跑费用流即可。
C++ Code:
#include<bits/stdc++.h> using namespace std; #define T 7000 #define N 7005 #define LoveLive long long #define inf 0x3f3f3f3f int n,p,m,f,nn,s,h[2005]; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct Graph{ std::queue<int>q; int head[N],cnt,pre_e[N],a[N]; LoveLive d[N]; bool vis[N]; struct edge{ int from,to,cap,cost,nxt; }e[1000005]; inline void addedge(const int u,const int v,const int flow,const int cost){ e[++cnt]=(edge){u,v,flow,cost,head[u]}; head[u]=cnt; e[++cnt]=(edge){v,u,0,-cost,head[v]}; head[v]=cnt; } Graph():cnt(1){ memset(head,-1,sizeof head); } bool bfs(LoveLive& flow,LoveLive& cost){ memset(d,0x3f,sizeof d); memset(a,0x3f,sizeof a); memset(vis,0,sizeof vis); memset(pre_e,0,sizeof pre_e); d[0]=0; vis[0]=1; q.push(0); while(!q.empty()){ int u=q.front();q.pop(); vis[u]=0; for(int i=head[u];~i;i=e[i].nxt) if(e[i].cap&&d[e[i].to]>d[u]+e[i].cost){ d[e[i].to]=d[u]+e[i].cost; a[e[i].to]=min(a[u],e[i].cap); pre_e[e[i].to]=i; if(!vis[e[i].to]){ vis[e[i].to]=1; q.push(e[i].to); } } } if(d[T]>100000000000000000)return 0; flow+=a[T]; cost+=d[T]*a[T]; for(int i=T;i;i=e[pre_e[i]].from){ e[pre_e[i]].cap-=a[T]; e[pre_e[i]^1].cap+=a[T]; } return 1; } LoveLive ek(){ LoveLive flow=0,cost=0; while(bfs(flow,cost)); return cost; } }g; int main(){ n=readint(); for(int i=1;i<=n;++i)h[i]=readint(); p=readint(),m=readint(),f=readint(),nn=readint(),s=readint(); for(int i=1;i<=n;++i){ g.addedge(0,i,h[i],0); g.addedge(i+n,T,h[i],0); if(i+m<=n)g.addedge(i,i+n+m,inf,f); if(i+nn<=n)g.addedge(i,i+n+nn,inf,s); g.addedge(0,i+n,inf,p); if(i!=n)g.addedge(i,i+1,inf,0); } cout<<g.ek()<<endl; return 0; }