luoguP1251 餐巾计划问题 题解
题目描述
请自行去看
输入输出格式
请自行去看
样例/提示/说明
请自行去看
这道题看标签 显然是一道网络流题
也显然是一道最小费用最大流的题 , 不知道费用流去看看模板吧...
既然是一道网络流题 , 那就只讲建图
这道题听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();}