~~~题面~~~

题解:

这是一道强题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]贪吃的老鼠 网络流的更多相关文章

  1. Luogu2570 [ZJOI2010]贪吃的老鼠 ---- 网络流

    Luogu2570  [ZJOI2010]贪吃的老鼠 题面描述 https://www.luogu.org/problemnew/show/P2570 然后题意大概就是m只老鼠,然后吃n个奶酪,已知 ...

  2. 洛谷$P2570\ [ZJOI2010]$贪吃的老鼠 网络流+二分

    正解:网络流+二分 解题报告: 传送门$QwQ$ 和上一题有点儿像,,,?$QwQ$但是比上一题要有趣很多$QwQ$ 首先把大致思路捋下?依然是.二分出每个奶酪的开始和结束时间,然后check下最大流 ...

  3. [ZJOI2010]贪吃的老鼠(网络流+建图)

    题目描述 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块奶酪,其中第i块的大小为pi,会在第ri秒被生产出来,并且必须在第di秒之前将它吃掉.第j只老鼠吃 ...

  4. Luogu P2570 [ZJOI2010]贪吃的老鼠

    Luogu P2570 [ZJOI2010]贪吃的老鼠 题目描述 奶酪店里最近出现了\(m\)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产\(n\)块奶酪,其中第\(i\)块的 ...

  5. [ZJOI2010]贪吃的老鼠

    很不错的一道网络流的题目 二分答案是显然的 首先不考虑每个饼干只能一个老鼠吃 那很显然的建图就是将时间点按照开始结束的点分成2*n-1段 然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可 ...

  6. P2570 [ZJOI2010]贪吃的老鼠

    传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...

  7. Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流

    题目链接:https://www.luogu.org/problemnew/show/P2570 题意概述: 好像没什么好概述的.....很简洁? 分析: 首先想到二分时间,转化成判定性问题,在一定时 ...

  8. 【题解】ZJOI2010贪吃的老鼠

    %%%%真的好强...看题解我都看了好久才完全明白.放一下参考的博客,谢谢神犇QAQ 1号博客    2号博客(超级赞的啦) 因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在 ...

  9. luogu P2570 [ZJOI2010]贪吃的老鼠【二分+最大流】

    首先考虑只满足第一个条件,二分答案,把过期时间加上mid之后的2n个时间离散,老鼠拆成每个时间的,第i个时间第j个老鼠为id[i][j],连接(s,i,p[i]),对于离散后时间(g[j-1]~g[j ...

随机推荐

  1. Putty远程连接Ubuntu14.04

    步骤一.在ubuntu系统中安装ssh,可使用如下的命令进行安装: sudo apt-get install openssh-server 步骤二.为了保险起见,安装完成后重启一下ssh服务,命令如下 ...

  2. Python对象引用问题总结

    对于对象引用问题,一直是一知半解的状态,现整理以备使用. 操作不可变对象进行加减运算时,会在内存中创建新的不可变实例,不会影响原来的引用>>> c=12>>> d= ...

  3. 「日常训练」Alternative Thinking(Codeforces Round #334 Div.2 C)

    题意与分析 (CodeForces - 603A) 这题真的做的我头疼的不得了,各种构造样例去分析性质... 题意是这样的:给出01字符串.可以在这个字符串中选择一个起点和一个终点使得这个连续区间内所 ...

  4. 跟浩哥学自动化测试Selenium -- 我的第一个Demo (2)

    我的第一个Demo 开始写第一个 Demo 之前,先熟悉一下编写 Selenium 脚本的四个步骤: 驱动路径写法分析:System.setProperty 主要做用是设置系统属性,第一个参数为系统属 ...

  5. 在nginx环境下,直接用域名访问(首页)

    ①: server { listen 80; server_name www.njm1.com; location = / { #=/规则可以直接访问域名.如:www.njm1.com.跳转到http ...

  6. Unity操作小技巧

    1.操作类 1)F:选择物体后聚焦 2)V:选择物体的顶点,顶点吸附 3)Ctrl:摁住后拖动物体,可以按照系统设置的步长进行移动(Edit -> Snap setting) 4)Q W E R ...

  7. 【picker】选择器组件说明

    picker从底部弹起选择器组件 组件细节: 1) 该组件有五种类型,分别是普通选择器.多列选择器.时间选择器.日期选择器.省市区选择器. 2) 组件内必需包裹内容,不然无法弹出选项 <!-- ...

  8. leetcode-三数之和(java)

     三数之和     给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可 ...

  9. CSP201703-1:分蛋糕

    引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...

  10. Dreamweaver CS5网页制作教程

    说到Dreamweaver这个网页制作神器,不由得想起在学校里上的选修课,那是的我们只知道 table 布局,只知道构建网站最方便的是使用“所见即所得”编辑器.回忆一下,真的是很怀旧啊! 虽说咱现在大 ...