[网络流24题] 餐巾
时间限制:5 s 内存限制:128 MB
【问题描述】
一个餐厅在相继的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天总的费用最小。
【输入】
输入文件共 3 行,第 1 行为总天数;第 2 行为每天所需的餐巾块数;第 3 行为每块餐巾的新购费用 p ,快洗所需天数 m ,快洗所需费用 f ,慢洗所需天数 n ,慢洗所需费用 s 。
【输出】
一行,最小的费用
【样例】
napkin.in
3
3 2 4
10 1 6 2 3
napkin.out
64
【数据规模】
n<=200,Ri<=50
还是要看题解才能写...
我们约定餐巾洗好之后当天就用,这样脏餐巾可以放几天再去洗。
我们将每一天看做两个点,对于第i天,拆成i<<1和i<<1|1,第一个点表示当天需要的餐巾,第二个点表示截止目前剩下的脏餐巾。
那么将s与每一个i<<1连边,流量大小为a[i],权值为p,再将i<<1连向t,流量为a[i],权值为0,这种情况下求得最大流时的费用便是每天的餐巾都新买的费用。
再讲s与i<<1|1连一条边,流量也为a[i],权值为0,表示当天用完餐巾会产生的脏餐巾,再把i<<1|1向(i+1)<<1|1连边,表示当天的脏餐巾可以留到第二天再洗,流量为inf,权值为0,对于两种洗餐巾,将i<<1|1,连向(i+d1)<<1,表示当天洗完的餐巾可以留给那一天用,流量为inf,权值为c1。跑一遍zkw即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=420; 4 const int inf=0x3fffffff; 5 int n,a[maxn],p,d1,c1,d2,c2; 6 int tot=-1,fi[maxn],next[maxn<<4],to[maxn<<4],cost[maxn<<4],flow[maxn<<4]; 7 int s,t,ans,que[maxn],head,tail,cur[maxn],dis[maxn],vis[maxn]; 8 void edge_add(int x,int y,int f,int c){ 9 to[++tot]=y;next[tot]=fi[x];fi[x]=tot;cost[tot]=c;flow[tot]=f; 10 to[++tot]=x;next[tot]=fi[y];fi[y]=tot;cost[tot]=-c;flow[tot]=0; 11 } 12 bool bfs(){ 13 head=tail=1; 14 que[++tail]=s; 15 for(int i=s;i<=t;i++)cur[i]=fi[i],dis[i]=inf,vis[i]=0; 16 dis[s]=0; 17 vis[s]=1; 18 while(head!=tail){ 19 head++; 20 if(head==410)head=1; 21 int u=que[head]; 22 vis[u]=0; 23 for(int i=fi[u];i+1;i=next[i]){ 24 if(flow[i]&&dis[to[i]]>dis[u]+cost[i]){ 25 dis[to[i]]=dis[u]+cost[i]; 26 if(!vis[to[i]]){ 27 vis[to[i]]=1; 28 tail++; 29 if(tail==410)tail=1; 30 que[tail]=to[i]; 31 } 32 } 33 } 34 } 35 return dis[t]!=inf; 36 } 37 int dfs(int x,int f){ 38 vis[x]=1; 39 if(x==t||!f)return f; 40 for(int i=cur[x];i+1;i=next[i]){ 41 cur[x]=i; 42 if(!vis[to[i]]&&flow[i]&&dis[to[i]]==dis[x]+cost[i]){ 43 int g=dfs(to[i],min(f,flow[i])); 44 if(g){//cout<<x<<" "<<g<<endl; 45 ans+=g*cost[i]; 46 flow[i]-=g; 47 flow[i^1]+=g; 48 return g; 49 } 50 } 51 } 52 return 0; 53 } 54 void zkw(){ 55 while(bfs()) 56 while(dfs(s,inf)); 57 printf("%d\n",ans); 58 } 59 int main() 60 { 61 scanf("%d",&n); 62 s=1;t=n*2+2; 63 memset(fi,-1,sizeof(fi)); 64 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 65 scanf("%d%d%d%d%d",&p,&d1,&c1,&d2,&c2); 66 for(int i=1;i<=n;i++){ 67 edge_add(s,i<<1,a[i],p); 68 edge_add(i<<1,t,a[i],0); 69 edge_add(s,i<<1|1,a[i],0); 70 if(i!=n)edge_add(i<<1|1,(i+1)<<1|1,inf,0); 71 if(i+d1<=n)edge_add(i<<1|1,(i+d1)<<1,inf,c1); 72 if(i+d2<=n)edge_add(i<<1|1,(i+d2)<<1,inf,c2); 73 } 74 zkw(); 75 return 0; 76 }