• NOIP2020


    T1:排水系统 

    题意:n 个排水节点(1 ... n),m 个接水口(1 ... m),0 个排水管道的为出水口。

    输入样例:
    5 1 3 2 3 5 2 4 5 2 5 4 0 0
    输出样例:
    1 3
    2 3
    画出样例数据当中的示意图,如下图所示:

    1、确定入水口:根据题意可知,有m个入水口,那么具体的口是(1,2,... ,m)

    2、确定出水口:根据题意可知,在输入数据当中,如果没有排出管道连到其他节点,那么即为出水口。根据输入为0的时候,用一个数组标记即可。

    3、在模拟流到其他节点的时候,怎么恰当的表示数据?肯定不能每次都用小数算出来,这样会有数精度的损失。那么根据流出管道的数量size,只要每次乘以一个size,即可得分流到该节点的水流量。这时候分为两种情况:

    1)假如是中间节点的话,那么只要不停的乘以这个size得到当前节点分母的大小,分子就一直都是1。然后加入队列。

    2)如果是最终流出节点的话,那么就每次从队列里取出一个节点之后,若该节点的下一个节点就是流出节点的话,那么加上第一个流入该节点的流量;若后面还有节点流到该流出节点的话,那么就累加起来:得到最终的ans_x[i], ans_y[i]。两个分数相加的简单方法就是先用最大公约数求出最小公倍数,然后最小公倍数除以各自的分母即为两个分子要乘的积。加起来之后再用最大公约数约一下分得到最简分数。

    因为本题的数据范围是:可能会到10-26,所以即使是long long也过不了。可以用double,然后对应的gcd改成 a - floor(a / b) * b即可。

     AC代码:

    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int N = 1e5 + 10;
    const double eps = 1e-18;
    #define int long long
    int n, m;
    double x[N], y[N], G;
    struct Node{
        int num, val;
    }b[N];
    bool st[N];
    vector<int> a[N];
    queue<Node> q;
    
    double gcd(double a, double b)
    {
        if(a < b) swap(a, b);
        if(b < eps) return a;
        return gcd(b, a - floor(a / b) * b);
    }
    
    void bfs()
    {
        while(q.size())
        {
            Node t = q.front(); q.pop();
            int Size = (int)a[t.num].size();
            t.val *= Size;
            for(int i = 0; i < Size; i ++)
            {
                int Y = a[t.num][i];
                if(st[Y])
                {
                    if(!x[Y] || !y[Y])
                    {
                        x[Y] = 1; y[Y] = t.val;
                        continue;
                    }
                    double g1 = gcd(y[Y], t.val), g = y[Y] / g1 * t.val;
                    x[Y] = g / y[Y] * x[Y] + g / t.val * 1;
                    y[Y] = g;
                    G = gcd(x[Y], y[Y]);
                    x[Y] /= G;
                    y[Y] /= G;
                    continue;
                }
                q.push({Y, t.val});
            }
        }
    }
    
    signed main()
    {
        scanf("%lld%lld", &n, &m);
        for(int i = 1; i <= n; i ++)
        {
            int T; scanf("%lld", &T);
            if(!T) { st[i] = 1; continue; }
            while(T --)
            {
                int x; scanf("%lld", &x);
                a[i].push_back(x);
            }
        }
        for(int i = 1; i <= m; i ++)
        {
            Node t; t.num = i; t.val = 1;
            q.push(t);
        }
        bfs();
        for(int i = 1; i <= n; i ++)
            if(st[i])
                printf("%.0lf %.0lf
    ", x[i], y[i]);
    }
    
  • 相关阅读:
    面试官:HashMap死循环形成的原因是什么?
    这几个IDEA高级调试技巧,用完就是香
    图示JVM工作原理
    写二进制,姿势一定要骚,省字段,省带宽,提效率...
    阿里大佬总结的40个多线程面试题,你能答上来几个?
    全网最全RabbitMQ总结,别再说你不会RabbitMQ
    .NETCore微服务探寻(三)
    .NETCore微服务探寻(二)
    .NETCore微服务探寻(一)
    谈谈spring-boot-starter-data-redis序列化
  • 原文地址:https://www.cnblogs.com/longxue1991/p/15552706.html
Copyright © 2020-2023  润新知