zoukankan      html  css  js  c++  java
  • Luogu2570 ZJOI2010 贪吃的老鼠 二分答案+最大流

    题目链接: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],两种情况达到最大值都是所有的边满流。

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

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 const int MAXN=35;
     14 const double eps=1e-7;
     15 
     16 int K,N,M,P[MAXN],R[MAXN],D[MAXN],S[MAXN];
     17 double sump;
     18 struct NET{
     19     static const int maxn=2005;
     20     static const int maxm=120000;
     21     static const double inf=1e9;
     22     struct edge{ int from,to,next; double cap,flow; }E[maxm];
     23     int n,s,t,first[maxn],np,d[maxn],gap[maxn],cur[maxn],fl[maxn];
     24     struct event{
     25         double p; int id;
     26         friend bool operator < (event x,event y){
     27             return x.p<y.p;
     28         }
     29     }e[65]; bool vis[35];
     30     NET(){ n=np=0,s=2001,t=2002; }
     31     void add_edge(int u,int v,double cap){
     32         E[++np]=(edge){u,v,first[u],cap,0};
     33         first[u]=np;
     34         E[++np]=(edge){v,u,first[v],0,0};
     35         first[v]=np;
     36     }
     37     void build(double m){
     38         memset(first,0,sizeof(first));
     39         np=n=0;
     40         for(int i=1;i<=N;i++) add_edge(++n,t,P[i]);
     41         int cnt=0;
     42         for(int i=1;i<=N;i++){
     43             e[++cnt]=(event){R[i],i};
     44             e[++cnt]=(event){D[i]+m,i};
     45         } 
     46         sort(e+1,e+cnt+1);
     47         memset(vis,0,sizeof(vis));
     48         int i=1,k=0;
     49         vis[e[1].id]^=1;
     50         while(i<cnt&&e[i+1].p-e[i].p<eps) vis[e[++i].id]^=1;
     51         double last=e[i++].p;
     52         while(i<=cnt){
     53             for(int j=1;j<=M;j++){
     54                 add_edge(s,n+k*M+j,j*S[j]*(e[i].p-last));
     55                 for(int l=1;l<=N;l++)
     56                     if(vis[l]) add_edge(n+k*M+j,l,S[j]*(e[i].p-last));
     57             }
     58             vis[e[i].id]^=1;
     59             while(i<cnt&&e[i+1].p-e[i].p<eps) vis[e[++i].id]^=1;
     60             k++,last=e[i++].p;
     61         }
     62         n+=k*M+2;
     63     }
     64     void BFS(){
     65         queue<int>q;
     66         for(int i=1;i<=n-2;i++) d[i]=n;
     67         d[s]=d[t]=n;
     68         q.push(t); d[t]=0;
     69         while(!q.empty()){
     70             int i=q.front(); q.pop();
     71             for(int p=first[i];p;p=E[p].next){
     72                 int j=E[p].to,pp=(p-1^1)+1;
     73                 if(d[j]==n&&fabs(E[pp].cap-E[pp].flow)>eps) d[j]=d[i]+1,q.push(j);
     74             }
     75         }
     76     }
     77     double augment(){
     78         int now=t; double flow=inf;
     79         while(now!=s){
     80             flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
     81             now=E[fl[now]].from;
     82         }
     83         now=t;
     84         while(now!=s){
     85             E[fl[now]].flow+=flow,E[(fl[now]-1^1)+1].flow-=flow;
     86             now=E[fl[now]].from;
     87         }
     88         return flow;
     89     }
     90     double ISAP(){
     91         memcpy(cur,first,sizeof(cur));
     92         memset(gap,0,sizeof(gap));
     93         BFS();
     94         for(int i=1;i<=n-2;i++) gap[d[i]]++;
     95         gap[d[s]]++,gap[d[t]]++;
     96         int now=s; double flow=0;
     97         while(d[s]<n){
     98             if(now==t) flow+=augment(),now=s;
     99             bool ok=0;
    100             for(int p=cur[now];p;p=E[p].next){
    101                 int j=E[p].to;
    102                 if(fabs(E[p].cap-E[p].flow)>eps&&d[j]+1==d[now]){
    103                     ok=1,fl[j]=cur[now]=p,now=j;
    104                     break;
    105                 }
    106             }
    107             if(!ok){
    108                 int minl=n;
    109                 for(int p=first[now];p;p=E[p].next){
    110                     int j=E[p].to;
    111                     if(fabs(E[p].cap-E[p].flow)>eps&&d[j]+1<minl) minl=d[j]+1;
    112                 }
    113                 if(--gap[d[now]]==0) break;
    114                 gap[d[now]=minl]++;
    115                 cur[now]=first[now];
    116                 if(now!=s) now=E[fl[now]].from;
    117             }
    118         }
    119         return flow;
    120     }
    121 }net;
    122 
    123 void data_in()
    124 {
    125     scanf("%d%d",&N,&M);
    126     for(int i=1;i<=N;i++) scanf("%d%d%d",&P[i],&R[i],&D[i]);
    127     for(int i=1;i<=M;i++) scanf("%d",&S[i]);
    128 }
    129 bool check(double mid)
    130 {
    131     net.build(mid);
    132     return fabs(net.ISAP()-sump)<eps;
    133 }
    134 bool cmp(int x,int y){ return x>y; }
    135 void work()
    136 {
    137     sort(S+1,S+M+1,cmp);
    138     for(int i=1;i<M;i++) S[i]=S[i]-S[i+1];
    139     sump=0;
    140     for(int i=1;i<=N;i++) sump+=P[i];
    141     double A=0,B=sump/S[M]+1.0,mid,ans;
    142     while(B-A>=eps){
    143         mid=(A+B)/2;
    144         if(check(mid)) ans=mid,B=mid;
    145         else A=mid;
    146     }
    147     printf("%f
    ",ans);
    148 }
    149 int main()
    150 {
    151     scanf("%d",&K);
    152     for(int i=1;i<=K;i++){
    153         data_in();
    154         work();
    155     }
    156     return 0;
    157 }
    View Code
  • 相关阅读:
    EF fluent API如何配置主键不自动增长
    简单的自定义Session
    使用NPOI,完成数据的导入导出
    c#索引器
    MUI框架 picker日期选择器实例
    使用MUI框架,模拟手机端的下拉刷新,上拉加载操作。
    Newtonsoft.Json
    NetMQ:.NET轻量级消息队列
    C#之RabbitMQ系列(一)
    C# 核心语法-反射(反射类型、方法、构造函数、属性,实现可配置可扩展,完成数据库访问类反射封装)
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8656738.html
Copyright © 2011-2022 走看看