题目链接:https://www.luogu.org/problemnew/show/P2570

题意概述:

  好像没什么好概述的.....很简洁?

分析:

  首先想到二分时间,转化成判定性问题,在一定时间内可不可以把奶酪吃完。

  对于判定性问题,能不能在限制下达成吃完这个指标,可以想到最大流来解决(求限制下吃蛋糕的最大体积)。

  把蛋糕的生产和过期看成两个事件,可以发现在事件发生的间隔所有老鼠的行为不会有新的选择出现,即能吃的奶酪就那些,问题的性质不发生改变。那么按照事件的发生和结束把事件间隔的时间段离散成一个个点,具体来说这一步是把老鼠拆开了。

    1.每个新点向时间段内存在的每个奶酪连边,容量为inf。

    2.源点向每个老鼠的点连边,容量为si*len,si表示老鼠吃奶酪的速度,len表示时间段的长度。

    3.每个奶酪向汇点连边,容量为奶酪的体积pi,只要奶酪向汇点连的边满流,那么奶酪就是吃完了。

  不难发现这样建图保证了每个老鼠只能在同一时间吃一块奶酪,因为我们限定了老鼠吃奶酪的最大体积,只要吃的体积满足限制,那么就一定不会同一时间吃多块奶酪,反之不合法。

  但是还没有保证一块奶酪只能被一只老鼠吃。此题最妙的地方就在对这里的处理,思考一下我们对上个限制的理解,只要限制了上界,那么就一定可以在合法意义下构造出一个方案!为了构造出合法方案,我们先把所有的速度降序排序,然后进行差分,把每只老鼠的速度变成v[i]=s[i]-s[i+1]。

    1.原点向每只老鼠连边,容量为len*i*v[i]。(这里的限制包含了对ii小于i的老鼠的限制)

    2.每只老鼠向奶酪连边,容量为len*v[i]。

    3.每块奶酪向汇点连边,容量为p[i]。

  解释一下,对于每只老鼠只能吃一块奶酪的限制,我们限制了所有老鼠吃奶酪总量的上界,因此一定可以构造出合法意义下的解。同事对于一个时间段内的奶酪,所有老鼠的速度最大为s[i],两种情况达到最大值都是所有的边满流。

  理解的关键:只要最后最大流满流,显然我们可以找到一种构造流量的方法,把差分之后的速度还原为原来的速度。还原流量的时候从小到大考虑。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int MAXN=;
const double eps=1e-; int K,N,M,P[MAXN],R[MAXN],D[MAXN],S[MAXN];
double sump;
struct NET{
static const int maxn=;
static const int maxm=;
static const double inf=1e9;
struct edge{ int from,to,next; double cap,flow; }E[maxm];
int n,s,t,first[maxn],np,d[maxn],gap[maxn],cur[maxn],fl[maxn];
struct event{
double p; int id;
friend bool operator < (event x,event y){
return x.p<y.p;
}
}e[]; bool vis[];
NET(){ n=np=,s=,t=; }
void add_edge(int u,int v,double cap){
E[++np]=(edge){u,v,first[u],cap,};
first[u]=np;
E[++np]=(edge){v,u,first[v],,};
first[v]=np;
}
void build(double m){
memset(first,,sizeof(first));
np=n=;
for(int i=;i<=N;i++) add_edge(++n,t,P[i]);
int cnt=;
for(int i=;i<=N;i++){
e[++cnt]=(event){R[i],i};
e[++cnt]=(event){D[i]+m,i};
}
sort(e+,e+cnt+);
memset(vis,,sizeof(vis));
int i=,k=;
vis[e[].id]^=;
while(i<cnt&&e[i+].p-e[i].p<eps) vis[e[++i].id]^=;
double last=e[i++].p;
while(i<=cnt){
for(int j=;j<=M;j++){
add_edge(s,n+k*M+j,j*S[j]*(e[i].p-last));
for(int l=;l<=N;l++)
if(vis[l]) add_edge(n+k*M+j,l,S[j]*(e[i].p-last));
}
vis[e[i].id]^=;
while(i<cnt&&e[i+].p-e[i].p<eps) vis[e[++i].id]^=;
k++,last=e[i++].p;
}
n+=k*M+;
}
void BFS(){
queue<int>q;
for(int i=;i<=n-;i++) d[i]=n;
d[s]=d[t]=n;
q.push(t); d[t]=;
while(!q.empty()){
int i=q.front(); q.pop();
for(int p=first[i];p;p=E[p].next){
int j=E[p].to,pp=(p-^)+;
if(d[j]==n&&fabs(E[pp].cap-E[pp].flow)>eps) d[j]=d[i]+,q.push(j);
}
}
}
double augment(){
int now=t; double flow=inf;
while(now!=s){
flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
now=E[fl[now]].from;
}
now=t;
while(now!=s){
E[fl[now]].flow+=flow,E[(fl[now]-^)+].flow-=flow;
now=E[fl[now]].from;
}
return flow;
}
double ISAP(){
memcpy(cur,first,sizeof(cur));
memset(gap,,sizeof(gap));
BFS();
for(int i=;i<=n-;i++) gap[d[i]]++;
gap[d[s]]++,gap[d[t]]++;
int now=s; double flow=;
while(d[s]<n){
if(now==t) flow+=augment(),now=s;
bool ok=;
for(int p=cur[now];p;p=E[p].next){
int j=E[p].to;
if(fabs(E[p].cap-E[p].flow)>eps&&d[j]+==d[now]){
ok=,fl[j]=cur[now]=p,now=j;
break;
}
}
if(!ok){
int minl=n;
for(int p=first[now];p;p=E[p].next){
int j=E[p].to;
if(fabs(E[p].cap-E[p].flow)>eps&&d[j]+<minl) minl=d[j]+;
}
if(--gap[d[now]]==) break;
gap[d[now]=minl]++;
cur[now]=first[now];
if(now!=s) now=E[fl[now]].from;
}
}
return flow;
}
}net; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++) scanf("%d%d%d",&P[i],&R[i],&D[i]);
for(int i=;i<=M;i++) scanf("%d",&S[i]);
}
bool check(double mid)
{
net.build(mid);
return fabs(net.ISAP()-sump)<eps;
}
bool cmp(int x,int y){ return x>y; }
void work()
{
sort(S+,S+M+,cmp);
for(int i=;i<M;i++) S[i]=S[i]-S[i+];
sump=;
for(int i=;i<=N;i++) sump+=P[i];
double A=,B=sump/S[M]+1.0,mid,ans;
while(B-A>=eps){
mid=(A+B)/;
if(check(mid)) ans=mid,B=mid;
else A=mid;
}
printf("%f\n",ans);
}
int main()
{
scanf("%d",&K);
for(int i=;i<=K;i++){
data_in();
work();
}
return ;
}

Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流的更多相关文章

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

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

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

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

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

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

  4. [ZJOI2010]贪吃的老鼠

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

  5. [ZJOI2010]贪吃的老鼠 网络流

    ---题面--- 题解: 这是一道强题emmmm,做法非常巧妙,,,我也是看了好久大佬题解才看明白一点 首先考虑没有限制的情况,即n个老鼠可以在同一时刻吃同一块奶酪 对各个时间段拆点,连奶酪 ---& ...

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

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

  7. BZOJ 1570: [JSOI2008]Blue Mary的旅行( 二分答案 + 最大流 )

    二分答案, 然后对于答案m, 把地点分成m层, 对于边(u, v), 第x层的u -> 第x+1层的v 连边. 然后第x层的u -> 第x+1层的u连边(+oo), S->第一层的1 ...

  8. BZOJ 1738: [Usaco2005 mar]Ombrophobic Bovines 发抖的牛( floyd + 二分答案 + 最大流 )

    一道水题WA了这么多次真是.... 统考终于完 ( 挂 ) 了...可以好好写题了... 先floyd跑出各个点的最短路 , 然后二分答案 m , 再建图. 每个 farm 拆成一个 cow 点和一个 ...

  9. BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

    题目大意:给定n个男生和n个女生,一些互相喜欢而一些不.举行几次舞会,每次舞会要配成n对.不能有同样的组合出现.每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会 将一个人拆成两个点.点1向点2连 ...

随机推荐

  1. LeetCode14.最长公共前缀 JavaScript

    编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...

  2. Django-rest-framework(五)自定义功能

    我们可以在settings.py文件中定义登录,权限,分页,异常等的全局配置,如下所示 REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'utils.pa ...

  3. oracle-sql脚本导出EXCEL数据

    在数据库中,经常有业务人员提出需求导出数据库中的业务数据,而且是每天.每周或每月定时导出.为了方便,可将sql查询的脚本 通过下面脚本来导出EXCEL数据. 1.将查询sql脚本(AAA.sql)放到 ...

  4. c/c++面试总结---c语言基础算法总结2

    c/c++面试总结---c语言基础算法总结2 算法是程序设计的灵魂,好的程序一定是根据合适的算法编程完成的.所有面试过程中重点在考察应聘者基础算法的掌握程度. 上一篇讲解了5中基础的算法,需要在面试之 ...

  5. N个数求和

    题目: 本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式. 输入格式: 输入第一行给出一个正整数N(≤100).随后一行按格式a ...

  6. 【PTA 天梯赛训练】修理牧场(哈夫曼树+优先队列)

    农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L​i​​个长度单位,于是他购买了一条很长的.能锯成N块的木头,即该木头的长度是L​i​​的总和. 但是农夫自己没有锯子,请 ...

  7. Ubuntu下安装Docker CE

    官网配置步骤:https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-docker-ce-1 安装Docker社区版仓库 Upd ...

  8. IDEA中使用插件添加更多可选择的主题,使代码高亮,缓解视觉疲劳

    1.点击 File-->settings(或Ctrl+Shift+S)打开IDE设置面板 点击plugins-->右侧选择Marketplace-->搜索框中输入Material-- ...

  9. 为什么我用了$().height()还是对不齐呢?

    有一个这样的需求:有两个显示内容的框,要使他们高度一致,因为他们存放的内容多少和结构不一样,左边内容少,右边内容多.这就导致了右边会比左边高,解决方法就是超出部分用滚轮显示,那这时就先要调整右边的高度 ...

  10. Vue 2.0 组件库总结

    UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开 ...