题目大意
现有一个传动系统,包含了 N 个组合齿轮和 M 个链条。
每一个链条连接了两个组合齿轮 u 和 v ,并提供了一个传动比 。即如果只考虑这两个组合齿轮,编号为 u 的齿轮转动 x 圈,编号为 v 的齿轮会转动 y 圈。
传动比为正表示若编号为 u 的齿轮顺时针转动,则编号为 v 的齿轮也顺时针转动。传动比为负表示若编号为 u 的齿轮顺时针转动,则编号为 v 的齿轮会逆时针转动。
若不同链条的传动比不相容,则有些齿轮无法转动。我们希望知道,系统中的这个组合齿轮能否同时转动。
输入格式
有多组数据,第一行给定整数 T ,表示总的数据组数,之后依次给出 T 组数据。
每一组数据的第一行给定整数 n 和 m ,表示齿轮总数和链条总数。
之后有 M 行,依次描述了每一个链条,其中每一行给定四个整数u,v ,x 和 y,表示只考虑这一组联动关系的情况下,编号为 u 的齿轮转动 x 圈,编号为 v 的齿轮会转动 y 圈。
请注意, x 为正整数,而 y 为非零整数,但是 y 有可能为负数。
输出格式
输出 T 行,对应每一组数据。首先应该输出标识这是第几组数据,参见样例输出。
之后输出判定结果,如果N个组合齿轮可以同时正常运行,则输出Yes,否则输出No。
算法
- 带权并查集裸题 但是之前没接触过带权并查集 考试的时候也没打出来……
- 处理每个点到集合的代表元素的距离 这里体现为到代表元素的乘积
- 每次在处理的时候更新一下权值 具体操作看代码注释
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const double EPS = 1e-5;//精度
int fa[maxn];
double d[maxn];//注意必须是double类型
int flag;
int find(int x){//带权并查集 找代表元素加路径压缩 加更新权值
if(x == fa[x])return x;
int rt = find(fa[x]);
d[x] *= d[fa[x]];
return fa[x] = rt;
}
int main(){
int T;scanf("%d",&T);
int cnt = 0;
while(T--){
flag = 1;
cnt++;
int n,m;scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)fa[i] = i,d[i] = 1;
while(m--){
int x,y,a,b;scanf("%d%d%d%d",&x,&y,&a,&b);
int fx = find(x),fy = find(y);
double k = (double)a / b;
if(fx != fy)fa[fx] = fy,d[fx] = k * d[y] / d[x];//更新 画图手模比较好理解
else if(abs(d[x] / d[y] - k) >= EPS)flag = 0;//不能直接比较浮点数大小
}
if(!flag)printf("Case #%d: No
",cnt);
else printf("Case #%d: Yes
",cnt);
}
return 0;
}