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\n", x[i], y[i]);
}

 

posted @ 2021-11-14 18:08  龙雪可可  阅读(37)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************