[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\n",tmp);  
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/yinwuxiao/p/8540180.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值