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

    很不错的一道网络流的题目

    二分答案是显然的

    首先不考虑每个饼干只能一个老鼠吃

    那很显然的建图就是将时间点按照开始结束的点分成2*n-1段

    然后对每一段时间建m个老鼠的点,然后s-它限流,再从它到目前可以运行的饼干

    那么考虑加上限制每个饼干只能被一个老鼠吃

    我们可以考虑一下进行差分

    将s-老鼠的值变成差分后的值(当然还得乘以相应个数) 同理老鼠到饼干也类似的连(就不用乘以相应个数了)

    为什么这样做是可以的呢?

    因为 我们可以把每一个决策都用这里差分的值来表示出来

    那还有一个问题就是有的状态实际上是看似不存在的

    比如有v1,v2,v3

    那么如果没有v2-v1,v1只有v3-v2这个状态实际是不存在的

    但是这个一定是比v3状态吃的要小的,即用比限制时间少的v3是一定能达到这个状态的

    所以这个是对的

    另外:由于几乎没用过c++实数的原因 被坑的很惨 

    刚开始以为是eps出问题导致精度不足。。后来发现对于精度要求高这不能用cout

    long double在精度上高于double

    输出时要转换成double输出

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const ll maxn=200000;
    #define INF 1e9
    #define exp 1e-6
    ll n,m,s,t,l,sum;
    ll head[maxn],d[maxn],p[maxn],r[maxn];
    ll dd[maxn],ss[maxn];
    bool vis[maxn];
    struct re{
        ll a,b;
        long double c,flow;
    }a[maxn];
    void arr(ll x,ll y,long double z)
    {
        a[++l].a=head[x];
        a[l].b=y;
        a[l].c=z;
        a[l].flow=0;
        head[x]=l;
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue<ll> q;
        q.push(s);
        d[s]=0; vis[s]=1;
        while (!q.empty())
        {
            ll x=q.front();q.pop();
            ll u=head[x];
            while (u)
            {
                ll v=a[u].b;
                if (!vis[v]&&a[u].c>a[u].flow)
                {
                    vis[v]=1;
                    d[v]=d[x]+1;
                    q.push(v);
                }
                u=a[u].a;
            }
        }
        return vis[t];
    }
    long double dfs(ll x,long double y)
    {
        if (x==t||y==0) return y;
        long double flow=0,f;
        ll tmp;
        ll u=head[x];
        while (u)
        {
            ll v=a[u].b;
            if (d[x]+1==d[v]&&(f=dfs(v,min(y,a[u].c-a[u].flow)))>0)
            {
                a[u].flow+=f;
                if (u%2) tmp=u+1; else tmp=u-1;
                y-=f;
                a[tmp].flow-=f;
                flow+=f;
                if (y==0) break;
            }   
            u=a[u].a;
        }
        return flow;
    }
    long double maxflow()
    {
        long double flow=0;
        while (bfs())
        {
            flow+=dfs(s,INF);
        }
        return flow;
    }
    struct ree{
        long double a;
        ll b;
    }b[maxn];
    bool cmp(ree a,ree b)
    {
        return(a.a<b.a);
    }
    bool cmp2(ll x,ll y)
    {
        return(x<y);
    }
    bool check(long double x)
    {
        for (ll i=1;i<=n;i++)
        {
            b[i*2-1].a=r[i]; b[i*2].a=dd[i]+x;
            b[i*2].b=i*2; b[i*2-1].b=i*2-1;
        }
        sort(b+1,b+2*n+1,cmp);
        l=0;memset(head,0,sizeof(head));
        ll last2=0;
        s=0; t=(2*n-1)*m+n+1;    
        for (ll i=1;i<=n;i++)
        {
            arr((2*n-1)*m+i,t,p[i]);
            arr(t,(2*n-1)*m+i,0);
        }
        for (ll i=1;i<=2*n-1;i++)
        {
            for (ll j=1;j<=m;j++)
            {
                arr(0,j+last2,(m-j+1)*(ss[j]-ss[j-1])*(b[i+1].a-b[i].a));
                arr(j+last2,0,0);
            }
            for (ll k=1;k<=n;k++)
              if (r[k]<=b[i].a&&dd[k]+x>=b[i+1].a)
                for (ll j=1;j<=m;j++)
                {
                    arr(j+last2,(2*n-1)*m+k,(b[i+1].a-b[i].a)*(ss[j]-ss[j-1]));
                    arr((2*n-1)*m+k,j+last2,0);
                }
            last2+=m;
        }
        ll to=maxflow();
        if (to==sum) return(1);
        else return (0);
    }
    int main()
    {
        freopen("cheese.in","r",stdin);
        freopen("cheese.out","w",stdout);
        ll T;
        cin>>T;
        for (ll i=1;i<=T;i++)
        {
            cin>>n>>m; sum=0;
            for (ll i=1;i<=n;i++)
            {
              cin>>p[i]>>r[i]>>dd[i];
              sum+=p[i];
            }
            for (ll i=1;i<=m;i++)
              cin>>ss[i];
            sort(ss+1,ss+m+1,cmp2);
            long double hh=0,tt=1e9;
            while ((tt-hh)>exp)
            {
             
                long double mid=(hh+tt)/2;
                if (check(mid)) tt=mid; else hh=mid;
            }
            double tmp=tt;
            printf("%.9f
    ",tmp);  
        }
        return 0;
    }
  • 相关阅读:
    20201029模拟赛总结
    20201023模拟赛总结
    贪心题目选讲
    博客阅览帮助
    NTT&FFT(快速?变换,以及扩展)
    数论知识小结 [基础篇]
    数论知识小结 [微提高篇]
    零化多项式/特征多项式/最小多项式/常系数线性齐次递推
    牛顿迭代快速求解定义域为多项式的函数零点
    求导/泰勒展开
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8540180.html
Copyright © 2011-2022 走看看