luoguP1251 餐巾计划问题 题解

luogu P1251 餐巾计划问题


 

题目描述

请自行去看

输入输出格式

请自行去看

样例/提示/说明

请自行去看


 

这道题看标签 显然是一道网络流题

也显然是一道最小费用最大流的题 , 不知道费用流去看看模板吧...

既然是一道网络流题 , 那就只讲建图


 

这道题听qc神仙说是上下界网络流 , 当然我也不知道那是啥

正常建图经过简单尝试后发现似乎不太可做 , 所以反过来想

但是好像有正着建图的方法


 

很显然能想到 , 这题需要拆点 , 我一开始甚至想拆餐巾 , 但是并没有做出来 , 所以就来拆 天

一天早晨进毛巾 , 晚上出毛巾 , 那么就想当然的可以把天拆成早和晚 , 分别进毛巾和出毛巾

但是我还是不会做....

那么反过来想 , 晚上其实是本有毛巾 , 那是不是就可以从原点( 脏/净 毛巾发售商)获得每天需要的毛巾数量的脏毛巾

而从早晨出去到汇点连边 , 流量也是毛巾需求量 , 可以代表用了这么多的干净毛巾然后变成了脏毛巾进了汇点

这样是两排点了 , 当然每条边花费是0 , 但是早晨的点没有入度

每天早晨 , 餐厅可以买进无限数量的毛巾 , 那么就可以从源点连向早晨点 , 流量无限 , 花费是p

再考虑洗餐巾 , 快洗慢洗需要时间 , 所以如果第 i 天洗毛巾需要k天 , 那么就可以把晚上 i 点和早晨 i+k 点连边 , 流量无限 , 花费也是题目给出的

又因为脏毛巾可以留给下一天等待解决 , 干净毛巾也可以考虑去留给下一天用 , 所以 i 点和 i+1 点也可以连流量无限花费0的边


 

这样就建完图了 , 然后一遍 spfa 最小费用流就过了

别忘了开 long long


 

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define APART puts("----------------------")
  9 #define debug 1
 10 #define inf 100010
 11 #define int long long
 12 #define ha 998244353
 13 #define INF 0x7fffffff
 14 #define INF_T 9223372036854775807
 15 #define DEBUG printf("%s %d\n",__FUNCTION__,__LINE__)
 16 using namespace std;
 17 
 18 namespace chino{
 19 
 20 inline int read(){
 21     char c = getchar(), up = c; int num = 0;
 22     for(; c < '0' || c > '9'; up = c, c = getchar());
 23     for(; c >= '0' && c <= '9';
 24     num = (num << 3) + (num << 1) + (c ^ '0'), c = getchar());
 25     return  up == '-' ? -num : num;
 26 }
 27 
 28 int n;
 29 int costP;
 30 int S, T;
 31 int cntE = -1;
 32 int costMin, flowMax;
 33 int fastDay, fastCost;
 34 int slowDay, slowCost;
 35 int need[inf];
 36 int head[inf];
 37 int cost[inf];
 38 int flow[inf];
 39 int vis[inf];
 40 int fat[inf];
 41 int last[inf];
 42 struct Edge{
 43     int to;
 44     int flow;
 45     int cost;
 46     int next;
 47 }e[inf << 1];
 48 queue<int>Q;
 49 
 50 inline void AddEdge(int from, int to, int flow, int cost){
 51     ++cntE;
 52     e[cntE].to = to;
 53     e[cntE].flow = flow;
 54     e[cntE].cost = cost;
 55     e[cntE].next = head[from];
 56     head[from] = cntE;
 57     return;
 58 }
 59 
 60 inline int spfa(int s, int t){
 61     memset(flow, 0x7f, sizeof flow);
 62     memset(cost, 0x7f, sizeof cost);
 63     memset(vis, 0, sizeof vis);
 64     Q.push(s);
 65     vis[s] = 1;
 66     cost[s] = 0;
 67     fat[t] = -1;
 68     while(!Q.empty()){
 69         int x = Q.front();
 70         Q.pop();
 71         vis[x] = 0;
 72         for(int i = head[x]; i ^ -1; i = e[i].next){
 73             int y = e[i].to;
 74             if(e[i].flow && cost[y] > cost[x] + e[i].cost){
 75                 cost[y] = cost[x] + e[i].cost;
 76                 fat[y] = x;
 77                 last[y] = i;
 78                 flow[y] = min(flow[x], e[i].flow);
 79                 if(vis[y] == 0)
 80                     vis[y] = 1,
 81                     Q.push(y);
 82             }
 83         }
 84     }
 85     return fat[t] ^ -1;
 86 }
 87 
 88 inline void work(int s, int t){
 89     int now = t;
 90     flowMax += flow[t];
 91     costMin += cost[t] * flow[t];
 92     while(now ^ s){
 93         e[last[now]].flow -= flow[t];
 94         e[last[now] ^ 1].flow += flow[t];
 95         now = fat[now];
 96     }
 97     return;
 98 }
 99 
100 inline void costDinic(int s, int t){
101     while(spfa(s, t))
102         work(s, t);
103     return;
104 }
105 
106 inline int main(){
107     memset(head, -1, sizeof head);
108     n = read();
109     for(int i = 1; i <= n; i++)
110         need[i] = read();
111     costP = read();
112     fastDay = read();
113     fastCost = read();
114     slowDay = read();
115     slowCost = read();
116     S = n << 1 | 1;
117     T = S + 1;
118     for(int i = 1; i <= n; i++){
119         AddEdge(S, i, need[i], 0);
120         AddEdge(i, S, 0, 0);
121 
122         AddEdge(i + n, T, need[i], 0);
123         AddEdge(T, i + n, 0, 0);
124 
125         AddEdge(S, i + n, INF >> 1, costP);
126         AddEdge(i + n, S, 0, -costP);
127     }
128     for(int i = 1; i < n; i++){
129         AddEdge(i, i + 1, INF >> 1, 0);
130         AddEdge(i + 1, i, 0, 0);
131 
132         AddEdge(i + n, i + n + 1, INF >> 1, 0);
133         AddEdge(i + n + 1, i + n, 0, 0);
134     }
135     for(int i = 1; i <= n; i++){
136         if(i + fastDay <= n){
137             AddEdge(i, i + fastDay + n, INF >> 1, fastCost);
138             AddEdge(i + fastDay + n, i, 0, -fastCost);
139         }
140         if(i + slowDay <= n){
141             AddEdge(i, i + slowDay + n, INF >> 1, slowCost);
142             AddEdge(i + slowDay + n, i, 0, -slowCost);
143         }
144     }
145     costDinic(S, T);
146     printf("%lld\n", costMin);
147     return 0;
148 }
149 
150 }//namespace chino
151 
152 signed main(){return chino::main();}

 

Chiaro的luogu blog文章

posted @ 2019-08-11 21:57  ChiaroShiro  阅读(197)  评论(0编辑  收藏  举报