zoukankan      html  css  js  c++  java
  • Luogu P2570 [ZJOI2010]贪吃的老鼠

    Luogu P2570 [ZJOI2010]贪吃的老鼠

    题目描述

    奶酪店里最近出现了(m)只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉。奶酪店中一天会生产(n)块奶酪,其中第(i)块的大小为(pi),会在第(ri)秒被生产出来,并且必须在第(di)秒之前将它吃掉。第j只老鼠吃奶酪的速度为(sj),因此如果它单独吃完第i快奶酪所需的时间为(pi/sj)。老鼠们吃奶酪的习惯很独特,具体来说:

    (1) 在任一时刻,一只老鼠最多可以吃一块奶酪;

    (2) 在任一时刻,一块奶酪最多被一只老鼠吃。

    由于奶酪的保质期常常很短,为了将它们全部吃掉,老鼠们需要使用一种神奇的魔法来延长奶酪的保质期。将奶酪的保质期延长(T)秒是指所有的奶酪的(di)变成(di+T)。同时,使用魔法的代价很高,因此老鼠们希望找到最小的T使得可以吃掉所有的奶酪。

    输入格式:

    输入文件的第一行包含一个整数(K),表示输入文件中数据的组数。

    每组数据的第一行包含两个整数(n)(m),分别表示奶酪和老鼠的数量。接下来的(n)行每行包含三个整数(pi,ri,di)。最后m行每行包含一个整数,表示(sj。pi,ri,di,sj)的含义如上文所述。

    输出格式:

    包含(K)行,每行包含一个实数,表示你找到的最小的(T)。你的答案和标准答案的绝对误差不应超过(10−4)

    数据范围

    100%的数据中,(1≤K≤5,1≤n,m≤30,1≤pi≤10^5, 0 ≤ri<di≤10^7,1≤sj≤10^5。)


    二分答案后跑最大流检验。

    首先我们不考虑第(2)个限制。先把所有的时间点离散化,假设有(k)个时间段,然后我们将每只老鼠拆成(k)个点。从源点连到每个点,容量为(s_i*len)。第(i)只老鼠在这个时间段的吃奶酪上限为(s_i*len),所以就满足了第一个限制。每个奶酪与在(r_i)(d_i)之间的时间段连边,然后再连向汇点,容量为(p_i)

    现在要考虑第(2)个限制。大致思路不变,只是我们要进行一些巧妙(根本想不到)的变换。将所有老鼠按(s)排序。第(i)只老鼠的新的速度为差分(t_i=s_i-s_{i-1})。第(i)个老鼠的第(j)个时间点与源点之间的边的容量为(s_i*len*(n-i+1))。其他不变。首先所有老鼠在某个时间段的吃奶酪数量总和不变,然后我们考虑对第(i)个奶酪,它在某个时间段内被吃的总量上限为(len*sum t_i=len*s_n),也就是速度最快的那只老鼠。所以对于一个最大流,我们也可以构造出一个合法的情况。

    代码:

    #include<bits/stdc++.h>
    #define N 35
    #define eps 1e-6
    
    using namespace std;
    inline int Get() {
        int x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while('0'<=ch&&ch<='9') {
            x=(x<<1)+(x<<3)+ch-'0';
            ch=getchar();
        }
        return x;
    }
    int n,m;
    struct cheese {
        int p,r,d;
    }ch[N];
    int eat[N];
    struct road {
        int to,nxt;
        double flow;
    }s[N*N*N*10];
    int h[N*N<<1],cnt;
    double totflow;
    void Init() {
        memset(h,0,sizeof(h));
        cnt=1;
    }
    void add(int i,int j,double f) {
        s[++cnt]=(road) {j,h[i],f};h[i]=cnt;
        s[++cnt]=(road) {i,h[j],0};h[j]=cnt;
    }
    int S,T;
    queue<int>q;
    int dis[N*N<<1];
    bool vis[N*N<<1];
    bool dinic_bfs() {
        memset(dis,0x3f,sizeof(dis));
        dis[S]=0;
        q.push(S);
        while(!q.empty()) {
            int v=q.front();
            q.pop();
            vis[v]=0;
            for(int i=h[v];i;i=s[i].nxt) {
                int to=s[i].to;
                if(s[i].flow>eps&&dis[to]>dis[v]+1) {
                    dis[to]=dis[v]+1;
                    if(!vis[to]) {
                        vis[to]=1;
                        q.push(to);
                    }
                }
            }
        }
        return dis[T]<1e9;
    }
    
    double dfs(int v,double maxf) {
        if(v==T) return maxf;
        double ret=0;
        for(int i=h[v];i;i=s[i].nxt) {
            int to=s[i].to;
            if(s[i].flow>eps&&dis[to]==dis[v]+1) {
                double dlt=dfs(to,min(maxf,s[i].flow));
                s[i].flow-=dlt;
                s[i^1].flow+=dlt;
                ret+=dlt;
                maxf-=dlt;
                if(maxf<eps) break;
            }
        }
        return ret;
    }
    
    double dinic() {
        double ans=0;
        while(dinic_bfs()) {
            while(1) {
                double tem=dfs(S,1e9);
                if(tem<eps) break;
                ans+=tem;
            }
        }
        return ans;
    }
    
    vector<double>tim;
    bool chk(double ans) {
        Init();
        tim.clear();
        for(int i=1;i<=n;i++) {
            tim.push_back(ch[i].r);
            tim.push_back(ch[i].d+ans);
        }
        sort(tim.begin(),tim.end());
        tim.resize(unique(tim.begin(),tim.end())-tim.begin());
        int tot=m*(tim.size()-1);
        T=tot+n+1;
        int now=0;
        for(int i=1;i<=m;i++) {
            for(int j=0;j<tim.size()-1;j++) {
                now++;
                add(S,now,min(totflow,(double)eat[i]*(tim[j+1]-tim[j])*(m-i+1)));
                for(int k=1;k<=n;k++)
                    if(tim[j]+eps>=ch[k].r&&tim[j+1]<=ch[k].d+ans+eps) add(now,tot+k,min(totflow,(double)eat[i]*(tim[j+1]-tim[j])));
            }
        }
        for(int i=1;i<=n;i++) add(tot+i,T,ch[i].p);
        double Flow=dinic();
        return fabs(Flow-totflow)<eps;
    }
    
    int main() {
        int cas=Get();
        while(cas--) {
            n=Get(),m=Get();
            totflow=0;
            for(int i=1;i<=n;i++) {
                ch[i].p=Get();
                ch[i].r=Get();
                ch[i].d=Get();
                totflow+=ch[i].p;
            }
            for(int i=1;i<=m;i++) eat[i]=Get();
            sort(eat+1,eat+1+m);
            double mx=eat[m];
            for(int i=m;i>=1;i--) eat[i]-=eat[i-1];
            double l=0,r=(double)totflow/mx+1,mid;
            while(l+eps<r) {
                mid=(l+r)/2.0;
                if(chk(mid)) r=mid;
                else l=mid+eps;
            }
            cout<<fixed<<setprecision(5)<<l<<"
    ";
        }
        return 0;
    }
    
    
  • 相关阅读:
    HDU 1269 迷宫城堡 tarjan算法求强连通分量
    hrbust 1721 A + B = 0 map的应用
    关于vis标记
    poj 1703
    poj1961 kmp
    acm poj1260 dp
    矩阵链乘 hrbust 1600
    单源最短路径 hdu 2066
    最小生成树
    多维背包 hrbudt 1335 算法与追MM
  • 原文地址:https://www.cnblogs.com/hchhch233/p/11053538.html
Copyright © 2011-2022 走看看