题目

题目描述:
现有一个传动系统,包含了N个组合齿轮和M个链条。每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x  : y。
即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈。
传动比为正表示若编号为u的齿轮顺时针转动,则编号为v的齿轮也顺时针转动。
传动比为负表示若编号为u的齿轮顺时针转动,则编号为v 的齿轮会逆时针转动。
若不同链条的传动比不相容,则有些齿轮无法转动。我们希望知道,系统中的这N个组合齿轮能否同时转动。

输入描述:
有多组数据,第一行给定整数T,表示总的数据组数,之后依次给出T组数据。
每一组数据的第一行给定整数N和M,表示齿轮总数和链条总数。
之后有M行,依次描述了每一个链条,其中每一行给定四个整数u,v,x和y,表示只考虑这一组联动关系的情况下,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈。
请注意,x为正整数,而y为非零整数,但是y有可能为负数。
T ≤ 32,N ≤ 1000,M ≤ 10000且x与y的绝对值均不超过100

输出描述:
输出T行,对应每一组数据。首先应该输出标识这是第几组数据,参见样例输出。之后输出判定结果,如果N个组合齿轮可以同时正常运行,则输出Yes,否则输出No。


解析

前向星(专栏)+遍历的简单题(我没看出来的简单题)
这道题重点是在齿轮匹配的转化上面,我们该怎么定位呢?
  1. 这里着重要考虑的就是前向星的权值是什么?
  2. 回顾已知条件:我们知道相邻的两个齿轮所相对转动的圈数,也就是齿轮相对转动比例
  3. 所以这个也就是我们的权值了。但是怎么用呢?
  4. 根据这个权值,我们可以从上一个节点推导出下一个节点。所以我们假设比例为y/x(y为后一节点的相对转动圈数,x为前一节点的)。

然后就是写代码
  1. 按照前向星的方法,将前向星初始化(前向星可以看专栏)。
  2. 然后建立一个观测数组(visited数组),将所有节点遍历一遍(以第一个节点开始,并以第一个的相对转动圈数作为他的实际转动圈数)。
  3. 如果有和要求互斥的(本题为我们推导出的下一节点的转动圈数)就直接输出No,正常扫完所有节点就可以输出Yes了。
  4. 详情看我代码吧~


代码

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
//代码预处理区

const int MAX = 1e4 + 7;
int head[MAX], total = 0;
struct node {
    int v, next;
    double w;
} edge[MAX << 1];
double weight[MAX];
int visited[MAX], flag = 1;
//全局变量区

template<class T>inline void read(T& res);//整型快读函数
void add_edge(int u, int v, double w);
void dfs(int u, int fa);
//函数预定义区

int main() {
    int T; read(T);
    for (int cnt = 1; cnt <= T; cnt++) {
        int N, M; read(N); read(M);
        total = 0;
        memset(head, 0, sizeof head);
        for (int i = 1; i <= M; i++) {
            int u, v, x, y; read(u); read(v); read(x); read(y);
            add_edge(u, v, 1.0 * x / y);
            add_edge(v, u, 1.0 * y / x);
        }
        flag = 1;
        memset(visited, 0, sizeof visited);
        for (int i = 1; i <= N && flag; i++)
            if (!visited[i]) {
                weight[i] = 1.0;
                dfs(i, 0);
            }
        if (flag) printf("Case #%d: Yes\n", cnt);
        else printf("Case #%d: No\n", cnt);
    }
    return 0;
}
template<class T>inline void read(T& res) {
    char c; T flag = 1;
    while ((c = getchar()) < '0' || c > '9')
        if (c == '-')
            flag = -1;
    res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9')
        res = res * 10 + c - '0';
    res *= flag;
}
void add_edge(int u, int v, double w) {
    total++;
    edge[total].v = v;
    edge[total].w = w;
    edge[total].next = head[u];
    head[u] = total;
}
void dfs(int u, int fa) {
    visited[u] = 1;
    for (int i = head[u]; i; i = edge[i].next) {
        int v = edge[i].v;
        if (v != fa)
            if (visited[v])
                if (abs(weight[v] - weight[u] * edge[i].w) <= 1e-3);
                else {
                    flag = 0;
                    return;
                }
            else {
                weight[v] = weight[u] * edge[i].w;
                dfs(v, u);
            }
    }
}
//函数区