zoukankan      html  css  js  c++  java
  • 【题解】ZJOI2010贪吃的老鼠

    %%%%真的好强...看题解我都看了好久才完全明白。放一下参考的博客,谢谢神犇QAQ

    1号博客     2号博客(超级赞的啦)

     因为理解的过程太艰辛,所以必须记录一下这道强题:这道题目最难的两个约束就在于:保证一个时间一只老鼠只吃一块奶酪,一个时间一块奶酪只被一只老鼠吃。第一个想法还是相对明显的:二分答案,离散化时间节点(一个节点代表此节点到上一节点之间的时间段)。

     最妙的一处是老鼠的拆点。在我们之前离散出来的时间段中,每一段都维护m个老鼠的速度差值。我也不知道原作者是怎么想到建图方式的,所以无法解释思路的走向过程,只能说明一下建图的方式&为什么这样是对的。举个例子:我们现在有三只老鼠,速度分别是:5, 4, 3, 那么我们就可以认为是有3只速度为3(3 - 0 = 3)的老鼠,1只速度为1(4 - 3 = 1)的老鼠,还有一只速度为1(5 - 4 = 1)的老鼠。(为什么后面这两只不一样在后面会解释)。暂且将几只记为id,速度记为v。

     s-->每一块奶酪,流量为p[i]; 每一块奶酪-->这个时间段内的老鼠拆点,流量为老鼠拆点v*t(时间); 每一个老鼠拆点-->t,流量为id*v*t。现在让我们来看一下这张图是如何完美的满足了此题的1、2两条约束的:1.保证一个时间一只老鼠只吃一块奶酪:老鼠是按时间段拆的点,连向t,前面所说的拆为了3,1,1的情况,三条都流满说明三只老鼠都在吃,分别流量为1表明速度为3的老鼠在吃...这一点应该还是能够理解的,因为一一对应拆点,必然满足约束。2.保证一个时间一块奶酪只被一只老鼠吃:每一块奶酪都向不同的时间段的拆点通了流量,注意这里的流量并没有乘上id,所以都等于1*v*t,也就满足了一只老鼠的约束。

      以下是代码:(没有看懂的只要手抄一次代码,想必就能明白啦!)

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 100000
    #define eps 0.0000001
    #define INF 99999999.00 
    #define db double
    int n, m, s, t, cnp, head[maxn], lev[maxn], cur[maxn];
    db R, L, tot, p[maxn], r[maxn], d[maxn], T[maxn], v[maxn];
    struct edge
    {
        int to, last;
        db c;
    }E[maxn];
    
    bool cmp(db a, db b)
    {
        return a > b;
    }
    
    void add(int u, int v, db c)
    {
        E[cnp].to = v, E[cnp].last = head[u], E[cnp].c = c; head[u] = cnp ++;
        E[cnp].to = u, E[cnp].last = head[v], E[cnp].c = 0; head[v] = cnp ++;
    }
    
    bool bfs()
    {
        queue <int> q;
        memset(lev, 0, sizeof(lev));
        q.push(s); lev[s] = 1;
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            for(int i = head[u]; i != -1; i = E[i].last)
            {
                int v = E[i].to;
                if(!lev[v] && E[i].c > eps)
                {
                    lev[v] = lev[u] + 1;
                    if(lev[t]) return true;
                    q.push(v);
                }
            }
        }
        return false;
    }
    
    db dfs(int u, db nf)
    {
        if(u == t || nf < eps) return nf;
        bool done = false;
        db ff = 0.0;
        for(int i = cur[u]; i != -1; i = E[i].last)
        {
            int v = E[i].to;
            if(!nf) break;
            if(E[i].c > eps && lev[v] == lev[u] + 1)
            {
                done = true;
                db af = dfs(v, min(E[i].c, nf));
                cur[u] = i;
                nf -= af, ff += af;
                E[i].c -= af, E[i ^ 1].c += af;
            }
        }
        if(!done) lev[u] = -1;
        return ff;
    }
    
    db dinic()
    {
        db flow = 0.0;
        while(bfs())
        {
            memcpy(cur, head, sizeof(head));
            flow += dfs(s, INF);
        }
        return flow;
    }
    
    void init()
    {
        cnp = 0;
        memset(head, -1, sizeof(head));
    }
    
    void solve()
    {
        db sum = tot; s = 0, t = 2 * m * n + n + 1;
        int cnt = 0;
        while(R - L > eps)
        {
            db mid = (R + L) / 2.0;
            init();
            for(int i = 1; i <= n; i ++)
            {
                add(0, i, p[i]);
                T[2 * i - 1] = r[i], T[2 * i] = d[i] + mid;
            }
            sort(T + 1, T + 2 * n + 1), cnt = n;
            for(int i = 1; i <= m; i ++)
            {
                for(int j = 2; j <= 2 * n; j ++)
                {
                    if(T[j] - T[j - 1] < eps) continue;
                    ++ cnt; add(cnt, t, i * v[i] * (T[j] - T[j - 1]));
                    for(int k = 1; k <= n; k ++)
                    {
                        if(r[k] - T[j - 1] < eps && (d[k] + mid - T[j] > -eps))
                            add(k, cnt, v[i] * (T[j] - T[j - 1]));
                    }
                } 
            }
            db maxflow = dinic();
            if(sum - maxflow < eps) R = mid;
            else L = mid;
        }
        printf("%lf
    ", L);
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T --)
        {
            tot = 0.0;
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i ++)
            {
                scanf("%lf%lf%lf", &p[i], &r[i], &d[i]);
                tot += p[i];
            }
            for(int i = 1; i <= m; i ++) scanf("%lf", &v[i]);
            sort(v + 1, v + 1 + m, cmp);
            R = (db) tot / v[1] + 1.0, L = 0.0;
            for(int i = 1; i < m; i ++) v[i] -= v[i + 1];
            solve();
        }
        return 0;
    } 
  • 相关阅读:
    软件设计的哲学:第十七章 一致性
    软件设计的哲学:第十六章 修改现有代码
    软件设计的哲学: 第十五章 先写注释
    软件设计的哲学:第十四章 选个好名字
    软件设计的哲学:第十三章 注释应该描述代码中隐藏的内容
    软件设计的哲学:第二十章 为什么要写注释
    软件设计的哲学:第十一章 两次设计
    软件设计的哲学: 第十章 定义不存在错误
    软件设计的哲学: 第九章 合并还是分解
    软件设计的哲学:第八章 降低复杂性
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8476294.html
Copyright © 2011-2022 走看看