题意:

这是一道最小费用(费用指单价)最大流的题目。

首先,我们拆点,将一天拆成晚上和早上,每天晚上会受到脏餐巾(来源:当天早上用完的餐巾,在这道题中可理解为从原点获得),每天早上又有干净的餐巾(来源:购买、快洗店、慢洗店)。

1.从原点向每一天晚上连一条流量为当天所用餐巾x,费用为0的边,表示每天晚上从起点获得x条脏餐巾。

2.从每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边,每天白天,表示向汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用 。 3.从每一天晚上向第二天晚上连一条流量为INF,费用为0的边,表示每天晚上可以将脏餐巾留到第二天晚上(注意不是早上,因为脏餐巾在早上不可以使用)。

4.从每一天晚上向这一天+快洗所用天数t1的那一天早上连一条流量为INF,费用为快洗所用钱数的边,表示每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 。

5.同理,从每一天晚上向这一天+慢洗所用天数t2的那一天早上连一条流量为INF,费用为慢洗所用钱数的边,表示每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾 。

6.从起点向每一天早上连一条流量为INF,费用为购买餐巾所用钱数的边,表示每天早上可以购买餐巾 。 注意,以上6点需要建反向边!3~6点需要做判断(即连向的边必须<=n)

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 #define INF 2147483647
 7 #define LL long long
 8 using namespace std;
 9 const int maxn=1e5+10;
10 queue<int>q;
11 int n,m,m1,t1,m2,t2,num=-1,st,ed;
12 struct node{
13     int u,v,w,cost,next;
14 }G[maxn];
15 int b[maxn],head[maxn],pre[maxn],pos[maxn],max_flow[maxn];
16 LL dis[maxn];
17 bool vis[maxn];
18 void build(int u,int v,int w,int cost)
19 {
20     G[++num].u=u;G[num].v=v;G[num].w=w;G[num].cost=cost;G[num].next=head[u];head[u]=num;
21     G[++num].u=v;G[num].v=u;G[num].w=0;G[num].cost=-cost;G[num].next=head[v];head[v]=num;
22 }
23 bool spfa()
24 {
25     memset(vis,true,sizeof(vis));
26     vis[st]=false;
27     memset(dis,63,sizeof(dis));
28     dis[st]=0;
29     max_flow[st]=INF;
30     q.push(st);
31     while(!q.empty()){
32         int u=q.front();
33         vis[u]=true;
34         q.pop();
35         for(int i=head[u];i!=-1;i=G[i].next){
36             int v=G[i].v;
37             if(G[i].w>0&&dis[v]>dis[u]+G[i].cost){
38                 dis[v]=dis[u]+G[i].cost;
39                 pos[v]=u;
40                 pre[v]=i;
41                 max_flow[v]=min(max_flow[u],G[i].w);
42                 if(vis[v]){
43                     q.push(v);
44                     vis[v]=false;
45                 }
46             }
47         }
48     }
49     return dis[ed]<4557430888798830399;
50 }
51 LL flow()
52 {
53     LL ans=0;
54     while(spfa()){
55         ans+=max_flow[ed]*dis[ed];
56         for(int i=ed;i!=st;i=pos[i]){
57             G[pre[i]].w-=max_flow[ed];
58             G[pre[i]^1].w+=max_flow[ed];
59         }
60     }
61     return ans;
62 }
63 int main()
64 {
65     int x;
66     scanf("%d",&n);
67     st=0,ed=2*n+1;
68     memset(head,-1,sizeof(head));
69     for(int i=1;i<=n;i++){
70         scanf("%d",&x);
71         build(st,i,x,0);//每天晚上从起点获得x条脏餐巾
72         build(i+n,ed,x,0);//每天白天,向汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用
73     }
74     scanf("%d %d %d %d %d",&m,&t1,&m1,&t2,&m2);
75     for(int i=1;i<=n;i++){
76         if(i+1<=n) build(i,i+1,INF,0);//每天晚上可以将脏餐巾留到第二天晚上
77         if(i+t1<=n) build(i,i+n+t1,INF,m1);//每天晚上可以送去快洗部,在地i+t1天早上收到餐巾
78         if(i+t2<=n) build(i,i+n+t2,INF,m2);//每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾
79         build(st,i+n,INF,m);//每天早上可以购买餐巾
80     }
81     printf("%lld",flow());
82 }
02-11 22:50