[网络流24题] 餐巾

[网络流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 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 }
View Code

 

转载于:https://www.cnblogs.com/hyghb/p/8177377.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值