Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流
Luogu2570 [ZJOI2010]贪吃的老鼠
题面描述
https://www.luogu.org/problemnew/show/P2570
然后题意大概就是m只老鼠,然后吃n个奶酪,已知
- 每个奶酪体积为$p_i$
 - 每个奶酪原始保质期为$s_i到t_i$(在一个时间轴上的位置)
 - 每只老鼠吃奶酪的速度为$v_i$
 
要求
- 同一时刻老鼠不能被原谅(不能吃两块奶酪)
 - 同一时刻奶酪不能原谅(不能被两只老鼠吃)
 
老鼠吃奶酪的时间可以为小数,且一个老鼠“一生”可以吃多块奶酪,一块奶酪“一生”可以多次被吃
现在你可以为奶酪$+T\ s$,也就是对于所有奶酪$t_i += T$
现在让你最小化$T$
题解
<!--瞎BB开始-->
好像机房就我没写了......
反正是要看题解的,这辈子逃不开题解的......
但题解看不懂连生活都维持不了这样子......
<!--瞎BB结束-->
还是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$,我们记为容量,我们要证明非法状态的$流量 > 容量$,在网络流中不存在。
这个时候我们有两种情况:
- 速度更快的老鼠还可以吃且可以吃超额部分(超额部分就是引起一只老鼠需要在同一时间吃两个奶酪的部分),那么就可以分担这个老鼠的任务,所以不存在这样的非法状态
 - 速度更快的老鼠吃不完超额部分,那么这些老鼠一定是已经吃过了,所以根据差分上面$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$,所以状态不存在。
代码如下:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream> //User's Lib #include <cmath>
#include <algorithm> using namespace std; #define DEBUG_PORT
#define DEBUG #ifdef ONLINE_JUDGE
#undef DEBUG_PORT
#undef DEBUG
#endif #ifdef DEBUG_PORT
#if __cplusplus >= 201103L
#ifdef DEBUG
template<typename T>
extern inline void Debug(T tar){
cerr << tar << endl;
}
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
cerr << head << ' ';
Debug(mid, tail...);
}
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif
#else
# pragma message "Warning : C++11 Not Use"
#ifdef DEBUG
template <typename T>
extern inline void Debug(T tar){
cerr << tar << endl;
}
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template <typename T>
extern inline void Debug(T tar){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif
#endif
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename Head, typename T, typename... Tail>
extern inline void Debug(Head head, T mid, Tail... tail){
return ;
}
template <typename T>
extern inline void Debug(T tar){
return ;
}
# pragma GCC diagnostic pop
# pragma message "Warning : pragma used"
#endif char buf[], *pc = buf; extern inline void Main_Init(){
static bool INITED = false;
if(INITED) fclose(stdin), fclose(stdout);
else {
fread(buf, , , stdin);
INITED = true;
}
} static inline int read(){
int num = ;
char c, sf = ;
while(isspace(c = *pc++));
if(c == ) sf = -, c = *pc ++;
while(num = num * + c - , isdigit(c = *pc++));
return num * sf;
} namespace LKF{
template <typename T>
extern inline T abs(T tar){
return tar < ? -tar : tar;
}
template <typename T>
extern inline void swap(T &a, T &b){
T t = a;
a = b;
b = t;
}
template <typename T>
extern inline void upmax(T &x, const T &y){
if(x < y) x = y;
}
template <typename T>
extern inline void upmin(T &x, const T &y){
if(x > y) x = y;
}
template <typename T>
extern inline T max(T a, T b){
return a > b ? a : b;
}
template <typename T>
extern inline T min(T a, T b){
return a < b ? a : b;
}
} //Source Code const int MAXK = ;
const int MAXN = ;
const int MAXM = ;
const double INF = 1e16;
const double eps = 1e-; inline bool comp(const double &a, const double &b){
double tmp = a - b;//int???
if(fabs(tmp) < eps) return ;
return a > b ? : -;
} int s = MAXN - , t = s + ; struct Queue{
int s, t;
int q[MAXN];
Queue(){s = , t = ;}
inline void clear(){
s = , t = ;
}
inline bool empty(){
return s > t;
}
inline int size(){
return t - s + ;
}
inline void push(int tar){
q[++ t] = tar;
}
inline int front(){
return q[s];
}
inline void pop(){
s ++;
}
}; struct Graph{
int tot;
int beginx[MAXN], endx[MAXM], nxt[MAXM];
double res[MAXM];
Graph(){
tot = ;
}
inline void Init(){
tot = ;
memset(beginx, , sizeof(beginx));
}
inline void add_edge(int u, int v, double r){
// Debug(u, "->", v, "[label = \"", r, "\"]");//Debug...
nxt[++ tot] = beginx[u], beginx[u] = tot, endx[tot] = v, res[tot] = r;
nxt[++ tot] = beginx[v], beginx[v] = tot, endx[tot] = u, res[tot] = ;
}
}; struct ISap{
Graph g;
Queue mession;
double max_f;
int cur[MAXN], d[MAXN], num[MAXN], pre[MAXN];
inline void bfs(){
mession.clear();
mession.push(t);
memset(d, , sizeof(d));
memset(num, , sizeof(num));
d[t] = ;
int u, v;
while(!mession.empty()){
u = mession.front();
mession.pop();
num[d[u]] ++;
for(int i = g.beginx[u]; i; i = g.nxt[i]){
v = g.endx[i];
if(!d[v] && comp(g.res[i ^ ], )){
d[v] = d[u] + ;
mession.push(v);
}
}
}
}
inline double dfs(int u, double now_f){
if(u == t) return now_f;
double ret_f = ;
for(int &i = cur[u]; i; i = g.nxt[i]){
int v = g.endx[i];
if(comp(g.res[i], ) && d[u] == d[v] + ){
double ret = dfs(v, min(g.res[i], now_f));
ret_f += ret, now_f -= ret;
g.res[i] -= ret, g.res[i ^ ] += ret;
if(d[s] >= MAXN - || !comp(now_f, )) return ret_f;
}
}
if(-- num[d[u]] == ) d[s] = MAXN - ;
++ num[++ d[u]];
cur[u] = g.beginx[u];
return ret_f;
}
inline double ISAP(){
bfs();
max_f = ;
memcpy(cur, g.beginx, sizeof(cur));
while(d[s] < MAXN - )
max_f += dfs(s, INF);
return max_f;
}
}isap; int n, m, sum;
int p[MAXK], r[MAXK], d[MAXK], ss[MAXK];
double tmp_arr[MAXK << ];
int cnt; inline bool check(double tar){
cnt = ;
isap.g.Init();
for(int i = ; i <= n; i++)
tmp_arr[++ cnt] = r[i], tmp_arr[++ cnt] = d[i] + tar;
sort(tmp_arr + , tmp_arr + + cnt);
cnt = unique(tmp_arr + , tmp_arr + + cnt) - tmp_arr - ;
for(int i = ; i <= n; i++)
isap.g.add_edge(s, i, p[i]);
for(int i = ; i <= cnt; i++){
double lst = tmp_arr[i - ], tim = tmp_arr[i] - lst;
for(int j = ; j <= m; j++)
isap.g.add_edge(n + (i - ) * m + j, t, j * tim * ss[j]);
for(int j = ; j <= n; j++)
if(r[j] <= lst && d[j] + tar >= tmp_arr[i])
for(int k = ; k <= m; k++)
isap.g.add_edge(j, n + (i - ) * m + k, tim * ss[k]);
}
return !comp(isap.ISAP(), sum);
} int main(){
Main_Init();
int T = read();
while(T --){
n = read(), m = read();
sum = ;
for(int i = ; i <= n; i++)
sum += (p[i] = read()), r[i] = read(), d[i] = read();
for(int i = ; i <= m; i++)
ss[i] = read();
ss[m + ] = ;
int tmp = ss[];
sort(ss + , ss + + m, greater<int>());
for(int i = ; i <= m; i++)
ss[i] -= ss[i + ];
double l = , r = 1.0 * sum / tmp, mid;
while(fabs(r - l) > eps){
mid = (l + r) / 2.0;
if(check(mid)) r = mid;
else l = mid;
}
printf("%.5lf\n", mid);
}
Main_Init();
return ;
}
Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流的更多相关文章
- [ZJOI2010]贪吃的老鼠    网络流
		
---题面--- 题解: 这是一道强题emmmm,做法非常巧妙,,,我也是看了好久大佬题解才看明白一点 首先考虑没有限制的情况,即n个老鼠可以在同一时刻吃同一块奶酪 对各个时间段拆点,连奶酪 ---& ...
 - 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分
		
正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...
 - [ZJOI2010]贪吃的老鼠(网络流+建图)
		
题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出来,并且必须在第di秒之前将它吃掉.第j只老鼠吃 ...
 - Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流
		
题目链接:https://www.luogu.org/problemnew/show/P2570 题意概述: 好像没什么好概述的.....很简洁? 分析: 首先想到二分时间,转化成判定性问题,在一定时 ...
 - Luogu P2570 [ZJOI2010]贪吃的老鼠
		
Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的 ...
 - [ZJOI2010]贪吃的老鼠
		
很不错的一道网络流的题目 二分答案是显然的 首先不考虑每个饼干只能一个老鼠吃 那很显然的建图就是将时间点按照开始结束的点分成2*n-1段 然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可 ...
 - P2570 [ZJOI2010]贪吃的老鼠
		
传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...
 - 【题解】ZJOI2010贪吃的老鼠
		
%%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客 2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...
 - luogu P2570 [ZJOI2010]贪吃的老鼠【二分+最大流】
		
首先考虑只满足第一个条件,二分答案,把过期时间加上mid之后的2n个时间离散,老鼠拆成每个时间的,第i个时间第j个老鼠为id[i][j],连接(s,i,p[i]),对于离散后时间(g[j-1]~g[j ...
 
随机推荐
- mysql系列九、mysql语句执行过程及运行原理(分组查询和关联查询原理)
			
一.背景介绍 了解一个sql语句的执行过程,了解一部分都做了什么,更有利于对sql进行优化,因为你知道它的每一个连接.where.分组.子查询是怎么运行的,都干了什么,才会知道怎么写是不合理的. 大致 ...
 - 026_关于shell中的特殊变量$0 $n $* $@ $! $?
			
一. $n:获取当前执行的shell脚本的第N个参数,n=1..9,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来like${10}. $*:获取当前shell的所有参数,将所有的命令行参数 ...
 - 转载:编译安装Nginx(1.4)《深入理解Nginx》(陶辉)
			
原文:https://book.2cto.com/201304/19617.html 安装Nginx最简单的方式是,进入nginx-1.0.14目录后执行以下3行命令:./configuremakem ...
 - 使用console进行 性能测试 和 计算代码运行时间
			
原文:http://www.tuicool.com/articles/JrARVjv 对于前端开发人员,在开发过程中经常需要监控某些表达式或变量的值,如果使用用 debugger 会显得过于笨重,最常 ...
 - vue首次赋值不触发watch
			
可通过其immediate 属性进行配置,默认为false watch:{ "aaa":{ immediate:true, handler:function(){ } }
 - LeetCode(44): 通配符匹配
			
Hard! 题目描述: 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). ...
 - 【ES】match_phrase与regexp
			
刚开始接触es,由于弄不清楚match_phrase和regexp导致很多查询结果与预想的不同.在这整理一下. regexp:针对的是单个词项 match_phrase:针对的是多个词项的相对位置 它 ...
 - 【ES】学习3-请求体查询
			
1.空查询 GET /index_2014*/type1,type2/_search {} GET /_search { , } 2.查询表达式 DSL只需将查询语句传递给 query 参数 GET ...
 - GuzzleHttp 请求设置超时时间
			
之前调用一个三方的 WEB API,大量的请求超时,导致 PHP 进程被占用完.整个网站一直报 504. 其中一个优化措施就是对三方 API 调用设置超时时间. use GuzzleHttp\Clie ...
 - Codeforces 5C Longest Regular Bracket Sequence(DP+括号匹配)
			
题目链接:http://codeforces.com/problemset/problem/5/C 题目大意:给出一串字符串只有'('和')',求出符合括号匹配规则的最大字串长度及该长度的字串出现的次 ...