[ZJOI2010]贪吃的老鼠 网络流
题解:
这是一道强题emmmm,做法非常巧妙,,,我也是看了好久大佬题解才看明白一点
首先考虑没有限制的情况,即n个老鼠可以在同一时刻吃同一块奶酪
对各个时间段拆点,连奶酪 ---> 老鼠(反过来也是一样的,只不过不方便),相连的奶酪要符合时间段的限制,
相当于把老鼠拆成很多个小时刻,连向这个时刻它可以吃的奶酪,流量为它在这段时间内可以吃的奶酪总量,
限流可以在汇点到老鼠的路径上进行。
但这个并不能满足同一时刻一块奶酪只能被一个老鼠吃这个条件,因此我们对老鼠再拆点,
把每个老鼠拆成的小时刻再根据速度差分,
比如8 4 2 1,四只老鼠。差分后就是:
8 - 4 = 4;
4 - 2 = 2;
2 - 1 = 1;
1 - 1 = 1;
然后按照编号来定权值
流量就为编号 * 速度(差分后) * 时间;
为什么这样?
8 = 4 + 2 + 1 + 1
4 = 2 + 1 + 1
2 = 1 + 1
1 = 1
可以很明显看到这是一个三角形,且每层都是相同的数字,对应到我们差分数组,对于每个差分后的速度,刚好有编号个,
这样就可以保证总的流量合法了。
那为什么这样可以保证同一时刻只有一只老鼠呢?
可以这样感性的理解:
注意到任意一只老鼠都可以由差分数组凑出,那么不管网络流怎样跑出答案,我们都可以通过分解一下流量,加加减减之类的数学方法凑成这几只老鼠,因此是合法的。
也就是说网络流跑出的东西也许跟原图不一样,但它可以用来判断是否合法(满流即合法),这就够了。
因此我们二分答案,每次都重新建图,跑最大流,满流为true,else 为 false。
代码有点长(打的isap),改成dinic应该会短很多
(数组开这么小是卡常后的结果,,,,)
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 5000
#define ac 20000
#define eps 1e-6
int x, n, m, T, cnt, tmp, ss, tt;
int p[AC], v[AC], last[AC];
double all, ll, rr, mid, ans, addflow;
double r[AC], d[AC], haveflow[ac], t[AC];
int Head[AC], Next[ac], date[ac], tot;
int good[AC], have[AC], c[AC];
int q[AC], tail, head;
/*神奇的网络流,,,,
对每个时间点进行离散化*/
inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline void upmin(double &a, double b)
{
if(b < a) a = b;
} inline void add(int f, int w, double S)
{
date[++tot] = w, Next[tot] = Head[f], haveflow[tot] = S, Head[f] = tot;
date[++tot] = f, Next[tot] = Head[w], Head[w] = tot;
//printf("%d ---> %d %.4lf\n",f,w,S);
} bool bfs()
{
int x, now;
head = tail = ;
c[tt] = , have[] = , q[++tail] = tt;
while(head < tail)
{
x = q[++head];
for(R i = Head[x]; i ; i = Next[i])
{
now = date[i];
if(haveflow[i ^ ] && !c[now])
{
c[now] = c[x] + ;
q[++tail] = now;
++have[c[now]];
}
}
}
memcpy(good, Head, sizeof(Head));
return c[ss];
} void aru()
{
while(x != ss)
{
haveflow[last[x]] -= addflow;
haveflow[last[x] ^ ] += addflow;
x = date[last[x] ^ ];
}
ans += addflow;
} double isap()
{
int now; bool done;
x = ss, addflow = INT_MAX;
while(c[ss] != ac + )
{
if(x == tt) aru(), addflow = INT_MAX;
done=false;
for(R i = good[x]; i ; i = Next[i])
{
now = date[i];
if(c[now] == c[x] - && haveflow[i])
{
last[now] = i;
upmin(addflow, haveflow[i]);
good[x] = i;
done = true;
x = now;
}
}
if(!done)
{
int go = ac;
for(R i = Head[x]; i ; i = Next[i])
{
now = date[i];
if(haveflow[i] && c[now]) go = c[now];
}
if(!(--have[c[x]])) break;
++have[c[x] = go + ];
good[x] = Head[x];
if(x != ss) x = date[last[x] ^ ];//这是回到上一个节点啊
}
}
return ans;
} inline bool cmp(double a, double b)
{
return a > b;
} void pre()
{
tot = , all = ;
n = read() ,m = read();
for(R i = ; i <= n; i++)
{
p[i] = read(), r[i] = read(), d[i] = read();
all += (double)p[i];
}
for(R i = ; i <= m; i++) v[i] = read();
sort(v + , v + m + , cmp);//error!!!老鼠是m只!!!!不是n只!!!
rr = (double) all / (double)v[] + 1.0, ll = ;
for(R i = ; i < m; i++) v[i] -= v[i + ];//对速度差分
} void build()
{
tot = , ans = ;
memset(Head, , sizeof(Head));//应该要放这里重置吧
memset(have, , sizeof(have));
memset(c, , sizeof(c));
for(R i = ; i <= n; i++)
{
add(ss, i, p[i]);
t[ * i - ] = r[i], t[ * i] = d[i] + mid;//为离散化做准备
}
sort(t + , t + * n + );//准备离散化了
cnt = , tmp = n;//因为不能和前n个奶酪的编号重了
int a = * n;
t[a + ] = INT_MAX;//不然最后一个点进不来
for(R i = ; i <= a; i++)
if(t[i + ] - t[i] > eps) t[++cnt] = t[i];//去重
for(R i = ; i <= m; i++)//枚举老鼠
{
for(R j = ; j <= cnt; j++)//因为要两个时间点才组成一个时间段
{
++tmp;
add(tmp, tt, i * v[i] * (t[j] - t[j - ]));//连离散化的老鼠到汇点
for(R k = ; k <= n; k++)//枚举奶酪
{
if(r[k] - t[j-] < eps && (d[k] + mid - t[j] > - eps))
add(k, tmp, v[i] * (t[j] - t[j - ]));//连奶酪向老鼠
}//r可以小于t(早就开始了),所以负数也合法,后面是同理的,只是移项了tarjan123 }
}
} void half()
{
ss = * m * n + n + , tt = ss + ;//error!!!ss是要2 * m * n + n + 1啊
while(rr - ll > eps)
{
mid = (rr + ll) / 2.0;
build();
if(bfs() && all - isap() < eps) rr = mid;
else ll = mid;
//printf("%.4lf\n",ans);
//printf("%.4lf %.4lf\n\n",ll,rr);
}
printf("%lf\n", ll);
} void work()
{
T=read();
while(T--)
{
pre();
half();
} } int main()
{
// freopen("in.in","r",stdin);
//freopen("cheese.out","w",stdout);
work();
// fclose(stdin);
//fclose(stdout);
return ;
}
[ZJOI2010]贪吃的老鼠 网络流的更多相关文章
- Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流
Luogu2570 [ZJOI2010]贪吃的老鼠 题面描述 https://www.luogu.org/problemnew/show/P2570 然后题意大概就是m只老鼠,然后吃n个奶酪,已知 ...
- 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分
正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...
- [ZJOI2010]贪吃的老鼠(网络流+建图)
题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出来,并且必须在第di秒之前将它吃掉.第j只老鼠吃 ...
- Luogu P2570 [ZJOI2010]贪吃的老鼠
Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的 ...
- [ZJOI2010]贪吃的老鼠
很不错的一道网络流的题目 二分答案是显然的 首先不考虑每个饼干只能一个老鼠吃 那很显然的建图就是将时间点按照开始结束的点分成2*n-1段 然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可 ...
- P2570 [ZJOI2010]贪吃的老鼠
传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...
- Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流
题目链接:https://www.luogu.org/problemnew/show/P2570 题意概述: 好像没什么好概述的.....很简洁? 分析: 首先想到二分时间,转化成判定性问题,在一定时 ...
- 【题解】ZJOI2010贪吃的老鼠
%%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客 2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...
- luogu P2570 [ZJOI2010]贪吃的老鼠【二分+最大流】
首先考虑只满足第一个条件,二分答案,把过期时间加上mid之后的2n个时间离散,老鼠拆成每个时间的,第i个时间第j个老鼠为id[i][j],连接(s,i,p[i]),对于离散后时间(g[j-1]~g[j ...
随机推荐
- JQuery表单验证插件
使用jQuery的validate插件实现一个简单的表单验证 <!DOCTYPE html> <html> <head> <meta charset=&quo ...
- angualarjs $location服务
$location服务 angular使用内置的$location服务来监听.操作url,包括以下功能: - 获取.监听.改变地址栏的URL: - 与URL实现双向数据绑定(地址栏变动.前进后退或者点 ...
- unable to access android sdk add-on list and SDK 更新镜像设置
前记 国内的网络呀,真是操蛋!!!!!! unable to access android sdk add-on list 在 Android Studio 安装目录 bin/idea.propert ...
- 洪水!(Flooded! ACM/ICPC World Final 1999,UVa815)
题目描述:竞赛入门经典的习题4-10 解题思路:1.把各个网格想象成一个数组 2.排序 3.雨水总体积去铺满 //太懒了只写了求海拔 #include <stdio.h> #define ...
- 小程序解析html和富文本编辑内容【亲测有效】
首先去 https://github.com/icindy/wxParse 下载wxParse,只拷贝wxParse文件夹即可. 1.引入wxss @import "../../util/w ...
- python作业:三级菜单(第一周)
一.作业需求: 1. 运行程序输出第一级菜单 2. 选择一级菜单某项,输出二级菜单,同理输出三级菜单 3. 菜单数据保存在文件中 4. 让用户选择是否要退出 5. 有返回上一级菜单的功能 二.三级菜单 ...
- 有关WCSF的几点整理
本文示例代码 一.CreateNew Attribute实现属性注入 Steps: 1/ aspx创建某个服务的属性. 2/ 为其添加[CreateNew] Attribute. 3/ 页面继承自Mi ...
- linux 文件已经删除,但是空间没有释放的原因
监控系统报告一台服务器的空间满了,登陆后发现/tmp下有大量access_log文件,分析是Apache的日志文件很久没有清理了,确认并执行删除操作. 但是,问题来了,执行 rm /tmp/acces ...
- POJ 1815 Friendship(最大流最小割の字典序割点集)
Description In modern society, each person has his own friends. Since all the people are very busy, ...
- HDU 4169 Wealthy Family(树形DP)
Problem Description While studying the history of royal families, you want to know how wealthy each ...