Luogu2570 [ZJOI2010]貪吃的老鼠 ---- 網絡流

Luogu2570  [ZJOI2010]貪吃的老鼠

題面描述

https://www.luogu.org/problemnew/show/P2570

而後題意大概就是m只老鼠,而後吃n個奶酪,已知ios

  • 每一個奶酪體積爲$p_i$
  • 每一個奶酪原始保質期爲$s_i到t_i$(在一個時間軸上的位置)
  • 每隻老鼠吃奶酪的速度爲$v_i$

要求c++

  • 同一時刻老鼠不能被原諒(不能吃兩塊奶酪)
  • 同一時刻奶酪不能原諒(不能被兩隻老鼠吃)

老鼠吃奶酪的時間能夠爲小數,且一個老鼠「一輩子」能夠吃多塊奶酪,一塊奶酪「一輩子」能夠屢次被吃git

如今你能夠爲奶酪$+T\ s$,也就是對於全部奶酪$t_i += T$網絡

如今讓你最小化$T$spa

題解

<!--瞎BB開始-->code

好像機房就我沒寫了......blog

反正是要看題解的,這輩子逃不開題解的......排序

但題解看不懂連生活都維持不了這樣子......
<!--瞎BB結束-->get

仍是DL不能依靠,仍是本身看比較好博客

二分答案+最大流

建圖方式:

首先對全部時間點離散化,記兩個時間點之間的時間段長度爲$tim$,而後把老鼠從大到小排序最後加個數字0,差分獲得m個差分值,記爲d,依次編號爲$1,2,3...$

對奶酪建點,對時間點間的時間段拆點,拆成m個老鼠差分值

源點連向奶酪,容量 p

奶酪連向奶酪保質期內的時間段的老鼠差分點,容量爲 老鼠差分值*時間段長度

老鼠差分點連向終點,容量爲 老鼠差分值*時間段長度*老鼠差分點編號(排序後從大到小)

而後跑最大流,奶酪滿流即爲合法

下面配合一個實例來說解證實爲何這樣是對的(反正我是想不到的)

爲了區分老鼠速度和差分後的速度,咱們將拆出來的點稱爲「老鼠差分點「或」老鼠點「或指代意義的」點「

舉個例子

老鼠分別有速度7,4,2

差分獲得3,2,2

而後咱們假設時間段長度爲2

而後老鼠到t的流量限制爲6,8,12

而後和奶酪的流量限制爲6,4,4​

 

當且僅當這張圖全部奶酪到起點的邊滿流的時候有解,其中若是一個老鼠$x$在一個時間段內吃了奶酪$y$,那麼從該時間段$m-x$到$m$的老鼠差分點到奶酪$y$都會有流量$t*d_i$。這張圖的工做原理是比較簡單的(若是看不懂能夠參考一下其它DL的博客)

最主要難以證實的是題目須要知足的兩個要求。

  首先證實這張圖知足一個老鼠同一時間只吃一個奶酪

  若是一個從大到小排名第$k$的老鼠吃了同一時間段的$x$塊奶酪(若是不在同一時間段的話就不會有非法狀態,若是有重疊則重疊部分和這個問題等價),設第$i$塊奶酪吃了時間$t_i$,那麼咱們假設一個非法狀態,也就是$(\Sigma{t_i}) > tim$,也就是一個老鼠同時吃多塊奶酪,因此這個時候k號老鼠差分點產生的流量至少爲$\Sigma{(t_i)}*d_k$,咱們記爲流量,可是咱們對該老鼠的限制有$k*tim*d_k$,咱們記爲容量,咱們要證實非法狀態的$流量 > 容量$,在網絡流中不存在。

這個時候咱們有兩種狀況:

  1. 速度更快的老鼠還能夠吃且能夠吃超額部分(超額部分就是引發一隻老鼠須要在同一時間吃兩個奶酪的部分),那麼就能夠分擔這個老鼠的任務,因此不存在這樣的非法狀態
  2. 速度更快的老鼠吃不完超額部分,那麼這些老鼠必定是已經吃過了,因此根據差分上面$k-1$個老鼠差分點對這個老鼠差分點產生了流量負擔,這個負擔加上原有的流量爲$\Sigma{(t_i)}*d_k+(k-1)*d_k*tim=k*tim*t_k+(\Sigma{(t_i)}-tim)$,因爲$(\Sigma{(t_i)}-tim)>0$,因此$\Sigma{(t_i)}*d_k+(k-1)*d_k*tim>k*d_k*tim$,因此$流量 > 容量$,在網絡流中沒法實現

  而後證實這張圖知足一個奶酪同時只被一隻老鼠吃

  這個比較簡單,同樣假設一共有x只老鼠吃了奶酪,每個吃了時間$t_i$,而後假設非法狀態$(\Sigma{t_i}) > tim$,而後因爲排名靠前的老鼠吃了的話那麼在差分點中對排名較後的老鼠也會有時間上的影響,也就是吃了同一個奶酪的排名最後的老鼠流量爲$\Sigma{(t_i)}*d_k$,大於邊的容量$ti*d_k$,因此狀態不存在。

 

代碼以下:

  1 #include <cstdio>
  2 #include <cctype>
  3 #include <cstring>
  4 #include <iostream>
  5 
  6 //User's Lib
  7 
  8 #include <cmath>
  9 #include <algorithm>
 10 
 11 using namespace std;
 12 
 13 #define DEBUG_PORT
 14 #define DEBUG
 15 
 16 #ifdef ONLINE_JUDGE
 17 #undef DEBUG_PORT
 18 #undef DEBUG
 19 #endif
 20 
 21 #ifdef DEBUG_PORT
 22 #if __cplusplus >= 201103L
 23 #ifdef DEBUG
 24 template<typename T>
 25 extern inline void Debug(T tar){
 26     cerr << tar << endl;
 27 }
 28 template<typename Head, typename T, typename... Tail>
 29 extern inline void Debug(Head head, T mid, Tail... tail){
 30     cerr << head << ' ';
 31     Debug(mid, tail...);
 32 }
 33 #else
 34 # pragma GCC diagnostic push
 35 # pragma GCC diagnostic ignored "-Wunused-parameter"
 36 template<typename Head, typename T, typename... Tail>
 37 extern inline void Debug(Head head, T mid, Tail... tail){
 38     return ;
 39 }
 40 # pragma GCC diagnostic pop
 41 # pragma message "Warning : pragma used"
 42 #endif
 43 #else
 44 # pragma message "Warning : C++11 Not Use"
 45 #ifdef DEBUG
 46 template <typename T>
 47 extern inline void Debug(T tar){
 48     cerr << tar << endl;
 49 }
 50 #else
 51 # pragma GCC diagnostic push
 52 # pragma GCC diagnostic ignored "-Wunused-parameter"
 53 template <typename T>
 54 extern inline void Debug(T tar){
 55     return ;
 56 }
 57 # pragma GCC diagnostic pop
 58 # pragma message "Warning : pragma used"
 59 #endif
 60 #endif
 61 #else
 62 # pragma GCC diagnostic push
 63 # pragma GCC diagnostic ignored "-Wunused-parameter"
 64 template<typename Head, typename T, typename... Tail>
 65 extern inline void Debug(Head head, T mid, Tail... tail){
 66     return ;
 67 }
 68 template <typename T>
 69 extern inline void Debug(T tar){
 70     return ;
 71 }
 72 # pragma GCC diagnostic pop
 73 # pragma message "Warning : pragma used"
 74 #endif
 75 
 76 char buf[11111111], *pc = buf;
 77 
 78 extern inline void Main_Init(){
 79     static bool INITED = false;
 80     if(INITED) fclose(stdin), fclose(stdout);
 81     else {
 82         fread(buf, 1, 11111111, stdin); 
 83         INITED = true;           
 84     }
 85 }
 86 
 87 static inline int read(){
 88     int num = 0;
 89     char c, sf = 1;
 90     while(isspace(c = *pc++));
 91     if(c == 45) sf = -1, c = *pc ++;
 92     while(num = num * 10 + c - 48, isdigit(c = *pc++));
 93     return num * sf;
 94 }
 95 
 96 namespace LKF{
 97     template <typename T>
 98     extern inline T abs(T tar){
 99         return tar < 0 ? -tar : tar;
100     }
101     template <typename T>
102     extern inline void swap(T &a, T &b){
103         T t = a;
104         a = b;
105         b = t;
106     }
107     template <typename T>
108     extern inline void upmax(T &x, const T &y){
109         if(x < y) x = y;
110     }
111     template <typename T>
112     extern inline void upmin(T &x, const T &y){
113         if(x > y) x = y;
114     }
115     template <typename T>
116     extern inline T max(T a, T b){
117         return a > b ? a : b;
118     }
119     template <typename T>
120     extern inline T min(T a, T b){
121         return a < b ? a : b;
122     }
123 }
124 
125 //Source Code
126 
127 const int MAXK = 33;
128 const int MAXN = 2018;
129 const int MAXM = 99999;
130 const double INF = 1e16;
131 const double eps = 1e-6;
132 
133 inline bool comp(const double &a, const double &b){
134     double tmp = a - b;//int???
135     if(fabs(tmp) < eps) return 0;
136     return a > b ? 1 : -1;
137 }
138 
139 int s = MAXN - 10, t = s + 1;
140 
141 struct Queue{
142     int s, t;
143     int q[MAXN];
144     Queue(){s = 1, t = 0;}
145     inline void clear(){
146         s = 1, t = 0;
147     }
148     inline bool empty(){
149         return s > t;
150     }
151     inline int size(){
152         return t - s + 1;
153     }
154     inline void push(int tar){
155         q[++ t] = tar;
156     }
157     inline int front(){
158         return q[s];
159     }
160     inline void pop(){
161         s ++;
162     }
163 };
164 
165 struct Graph{
166     int tot;
167     int beginx[MAXN], endx[MAXM], nxt[MAXM];
168     double res[MAXM];
169     Graph(){
170         tot = 1;
171     }
172     inline void Init(){
173         tot = 1;
174         memset(beginx, 0, sizeof(beginx));
175     }
176     inline void add_edge(int u, int v, double r){
177         // Debug(u, "->", v, "[label = \"", r, "\"]");//Debug...
178         nxt[++ tot] = beginx[u], beginx[u] = tot, endx[tot] = v, res[tot] = r;
179         nxt[++ tot] = beginx[v], beginx[v] = tot, endx[tot] = u, res[tot] = 0;
180     }
181 };
182 
183 struct ISap{
184     Graph g;
185     Queue mession;
186     double max_f;
187     int cur[MAXN], d[MAXN], num[MAXN], pre[MAXN];
188     inline void bfs(){
189         mession.clear();
190         mession.push(t);
191         memset(d, 0, sizeof(d));
192         memset(num, 0, sizeof(num));
193         d[t] = 1;
194         int u, v;
195         while(!mession.empty()){
196             u = mession.front();
197             mession.pop();
198             num[d[u]] ++;
199             for(int i = g.beginx[u]; i; i = g.nxt[i]){
200                 v = g.endx[i];
201                 if(!d[v] && comp(g.res[i ^ 1], 0)){
202                     d[v] = d[u] + 1;
203                     mession.push(v);
204                 }
205             }
206         }
207     }
208     inline double dfs(int u, double now_f){
209         if(u == t) return now_f;
210         double ret_f = 0;
211         for(int &i = cur[u]; i; i = g.nxt[i]){
212             int v = g.endx[i];
213             if(comp(g.res[i], 0) && d[u] == d[v] + 1){
214                 double ret = dfs(v, min(g.res[i], now_f));
215                 ret_f += ret, now_f -= ret;
216                 g.res[i] -= ret, g.res[i ^ 1] += ret;
217                 if(d[s] >= MAXN - 4 || !comp(now_f, 0)) return ret_f;
218             }
219         }
220         if(-- num[d[u]] == 0) d[s] = MAXN - 4;
221         ++ num[++ d[u]];
222         cur[u] = g.beginx[u];
223         return ret_f;
224     }
225     inline double ISAP(){
226         bfs();
227         max_f = 0;
228         memcpy(cur, g.beginx, sizeof(cur));
229         while(d[s] < MAXN - 5)
230             max_f += dfs(s, INF);
231         return max_f;
232     }
233 }isap;
234 
235 int n, m, sum;
236 int p[MAXK], r[MAXK], d[MAXK], ss[MAXK];
237 double tmp_arr[MAXK << 1];
238 int cnt;
239 
240 inline bool check(double tar){
241     cnt = 0;
242     isap.g.Init();
243     for(int i = 1; i <= n; i++)
244         tmp_arr[++ cnt] = r[i], tmp_arr[++ cnt] = d[i] + tar;
245     sort(tmp_arr + 1, tmp_arr + 1 + cnt);
246     cnt = unique(tmp_arr + 1, tmp_arr + 1 + cnt) - tmp_arr - 1;
247     for(int i = 1; i <= n; i++)
248         isap.g.add_edge(s, i, p[i]);
249     for(int i = 2; i <= cnt; i++){
250         double lst = tmp_arr[i - 1], tim = tmp_arr[i] - lst;
251         for(int j = 1; j <= m; j++)
252             isap.g.add_edge(n + (i - 2) * m + j, t, j * tim * ss[j]);
253         for(int j = 1; j <= n; j++)
254             if(r[j] <= lst && d[j] + tar >= tmp_arr[i])
255                 for(int k = 1; k <= m; k++)
256                     isap.g.add_edge(j, n + (i - 2) * m + k, tim * ss[k]);
257     }
258     return !comp(isap.ISAP(), sum);
259 }
260 
261 int main(){
262     Main_Init();
263     int T = read();
264     while(T --){
265         n = read(), m = read();
266         sum = 0;
267         for(int i = 1; i <= n; i++)
268             sum += (p[i] = read()), r[i] = read(), d[i] = read();
269         for(int i = 1; i <= m; i++)
270             ss[i] = read();
271         ss[m + 1] = 0;
272         int tmp = ss[1];
273         sort(ss + 1, ss + 1 + m, greater<int>());
274         for(int i = 1; i <= m; i++)
275             ss[i] -= ss[i + 1];
276         double l = 0, r = 1.0 * sum / tmp, mid;
277         while(fabs(r - l) > eps){
278             mid = (l + r) / 2.0;
279             if(check(mid)) r = mid;
280             else l = mid;
281         }
282         printf("%.5lf\n", mid);
283     }
284     Main_Init();
285     return 0;
286 }
相關文章
相關標籤/搜索