loj 6008 餐巾计划 - 费用流
Posted yyf0309
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj 6008 餐巾计划 - 费用流相关的知识,希望对你有一定的参考价值。
容易想到需要把未使用的餐巾和已经使用的餐巾分开。
设$X_i$表示第$i$天已经的使用餐巾的点,设$Y_i$表示第$i$天还未使用的餐巾的点
我们知道使用过的餐巾数量 = 洗出来的餐巾数量 + 购买的餐巾数量(一个餐巾被多次洗出来算多次)。
右边是啥,我们不清楚,但是我们清楚每一天新增的使用过的餐巾的数量,所以源点向$X_i$连一条容量为$r_i$,费用为0的边。
接下来还有几种连边:
- $X_i$向$X_{i + 1}$连一条容量为$infty$,费用为0的边(使用过的餐巾还是使用过的,$i < n$)。
- $Y_i$向$Y_{i + 1}$连一条容量为$infty$,费用为0的边
- $X_i$向$Y_{i + M}$连一条容量为$infty$,费用为$F$的边
- $X_i$向$Y_{i + N}$连一条容量为$infty$,费用为$S$的边
对于第$i$天会用掉$r_i$的餐巾,所以$Y_i$向汇点连一条容量为$r_i$,费用为0的边。
还有一个购买餐巾,它直接会变成这一天的未使用过的餐巾,所以原点向$Y_i$连一条容量为$infty$,费用为$p$的边。
Code
1 /** 2 * loj 3 * Problem#6008 4 * Accepted 5 * Time: 701ms 6 * Memory: 636k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <queue> 12 using namespace std; 13 typedef bool boolean; 14 15 template <typename T> 16 void pfill(T* pst, const T* ped, T val) { 17 for ( ; pst != ped; *(pst++) = val); 18 } 19 20 typedef class Edge { 21 public: 22 int ed, nx, r, c; 23 24 Edge(int ed = 0, int nx = 0, int r = 0, int c = 0) : ed(ed), nx(nx), r(r), c(c) { } 25 } Edge; 26 27 typedef class MapManager { 28 public: 29 int* h; 30 vector<Edge> es; 31 32 MapManager() { } 33 MapManager(int n) { 34 h = new int[(n + 1)]; 35 pfill(h, h + n + 1, -1); 36 } 37 38 void addEdge(int u, int v, int r, int c) { 39 es.push_back(Edge(v, h[u], r, c)); 40 h[u] = (signed) es.size() - 1; 41 } 42 43 void addArc(int u, int v, int cap, int c) { 44 addEdge(u, v, cap, c); 45 addEdge(v, u, 0, -c); 46 } 47 48 Edge& operator [] (int p) { 49 return es[p]; 50 } 51 } MapManager; 52 53 const signed int inf = (signed) (~0u >> 1); 54 55 class Graph { 56 public: 57 int S, T; 58 MapManager g; 59 60 int *le; 61 int *f, *mf; 62 boolean *vis; 63 64 // be sure T is the last node 65 void set(int S, int T) { 66 this->S = S; 67 this->T = T; 68 f = new int[(T + 1)]; 69 le = new int[(T + 1)]; 70 mf = new int[(T + 1)]; 71 vis = new boolean[(T + 1)]; 72 pfill(vis, vis + T, false); 73 } 74 75 int spfa() { 76 queue<int> que; 77 pfill(f, f + T + 1, inf); 78 que.push(S); 79 f[S] = 0, le[S] = -1, mf[S] = inf; 80 while (!que.empty()) { 81 int e = que.front(); 82 que.pop(); 83 vis[e] = false; 84 for (int i = g.h[e], eu, w; ~i; i = g[i].nx) { 85 if (!g[i].r) 86 continue; 87 eu = g[i].ed, w = f[e] + g[i].c; 88 if (w < f[eu]) { 89 f[eu] = w, le[eu] = i, mf[eu] = min(mf[e], g[i].r); 90 if (!vis[eu]) { 91 vis[eu] = true; 92 que.push(eu); 93 } 94 } 95 } 96 } 97 if (f[T] == inf) 98 return inf; 99 int rt = 0; 100 for (int p = T, e; ~le[p]; p = g[e ^ 1].ed) { 101 e = le[p]; 102 g[e].r -= mf[T]; 103 g[e ^ 1].r += mf[T]; 104 rt += mf[T] * g[e].c; 105 } 106 return rt; 107 } 108 109 int min_cost() { 110 int rt = 0, delta; 111 while ((delta = spfa()) != inf) { 112 rt += delta; 113 // cerr << delta << ‘ ‘; 114 } 115 return rt; 116 } 117 } Graph; 118 119 int n; 120 int P, M, F, N, S; 121 int *require; 122 MapManager &g = Graph.g; 123 124 inline void init() { 125 scanf("%d", &n); 126 scanf("%d%d%d%d%d", &P, &M, &F, &N, &S); 127 require = new int[(n + 1)]; 128 g = MapManager(n << 1 | 1); 129 for (int i = 1; i <= n; i++) { 130 scanf("%d", require + i); 131 } 132 } 133 134 inline void solve() { 135 int T = n << 1 | 1; 136 Graph.set(0, T); 137 for (int i = 1; i <= n; i++) { 138 g.addArc(0, i, require[i], 0); 139 g.addArc(0, i + n, inf, P); 140 if (i < n) { 141 g.addArc(i, i + 1, inf, 0); 142 g.addArc(i + n, i + n + 1, inf, 0); 143 } 144 if (i + M <= n) 145 g.addArc(i, i + n + M, inf, F); 146 if (i + N <= n) 147 g.addArc(i, i + n + N, inf, S); 148 g.addArc(i + n, T, require[i], 0); 149 } 150 printf("%d ", Graph.min_cost()); 151 } 152 153 int main() { 154 init(); 155 solve(); 156 return 0; 157 }
以上是关于loj 6008 餐巾计划 - 费用流的主要内容,如果未能解决你的问题,请参考以下文章