NC20583 [SDOI2016]齿轮
题目
题目描述
现有一个传动系统,包含了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 3
1 2 3 5
2 3 5 -7
1 3 3 -7
3 3
1 2 3 5
2 3 5 -7
1 3 3 7
输出
Case #1: Yes
Case #2: No
题解
方法一
知识点:并查集。
用带权并查集维护齿轮之间的关系,用权值表示根节点转一圈,这个节点转的圈数。
路径压缩,将父节点到根节点的权值乘以自己的权值。
集合合并,对于节点 \(x\) 和 \(y\) 以及其根节点 \(rx\) 和 \(ry\) ,将 \(rx\) 合并到 \(ry\) 需要得到 \(rx\) 的新权值,即得到 \(rx\) 和 \(ry\) 的传动比,有:
\]
即四个齿轮的三个传动比相乘得到 \(rx\) 和 \(ry\) 的传动比再将 \(ry\) 圈数设为 \(1\) ,于是 \(w_{rx}\) 就等于 \(rx\) 与 \(ry\) 的传动比乘以 \(ry\) 的圈数 \(1\) 。
如果新加关系的两个点已经在一个关系集合中,那就检验是否合法:
\]
两者传动比是否相等,相等则合法。
注意精度问题,相等用小于误差表示。
时间复杂度 \(O(n + m\log n)\)
空间复杂度 \(O(n)\)
方法二
知识点:DFS,图论。
和并查集思路差不多,但建图时要建无向图,因为需要直到可能遍历时走的是反向的。给起点权值赋为 \(1\) ,其他节点根据传动比赋值,上一个节点乘以这个方向的传动比的倒数的结果即是这个点实际转多少圈。
如果遇到遍历到一个访问过的节点,那就判断实际权值和目前算出来的权值是否相等。
时间复杂度 \(O(n+m)\)
空间复杂度 \(O(n+m)\)
代码
方法一
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, m;
int fa[10007];
double w[10007];
int find(int x) {
if (fa[x] == x) return x;
int pre = fa[x];
fa[x] = find(fa[x]);
w[x] *= w[pre];
return fa[x];
}
bool merge(int x, int y, double r) {
int rx = find(x);
int ry = find(y);
if (rx == ry)
return abs(w[x] / w[y] - r) < 1e-6;
fa[rx] = ry;
w[rx] = 1 / w[x] * r * w[y];
return true;
}
bool solve() {
cin >> n >> m;
for (int i = 1;i <= n;i++) fa[i] = i, w[i] = 1;
bool flag = true;
for (int i = 0;i < m;i++) {
int u, v;
double x, y;
cin >> u >> v >> x >> y;
if (!flag) continue;
flag &= merge(u, v, x / y);
}
return flag;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
for (int i = 1;i <= t;i++) {
cout << "Case #" << i << ": ";
if (!solve()) cout << "No" << '\n';
else cout << "Yes" << '\n';
}
return 0;
}
方法二
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, m;
struct edge {
int to, nxt;
double w;
}e[10007 << 1];
int h[1007], cnt;
double vis[1007];
void add(int u, int v, double w) {
e[cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = h[u];
h[u] = cnt++;
}
bool dfs(int u) {
for (int i = h[u];~i;i = e[i].nxt) {
int v = e[i].to;
if (vis[v]) {
if (abs(vis[v] - vis[u] / e[i].w) > 1e-6) return false;
}
else {
vis[v] = vis[u] / e[i].w;
if (!dfs(v)) return false;
}
}
return true;
}
bool solve() {
cin >> n >> m;
for (int i = 1;i <= n;i++) h[i] = -1, vis[i] = 0;
cnt = 0;
for (int i = 0;i < m;i++) {
int u, v;
double x, y;
cin >> u >> v >> x >> y;
add(u, v, x / y);
add(v, u, y / x);
}
vis[1] = 1;
return dfs(1);
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
for (int i = 1;i <= t;i++) {
cout << "Case #" << i << ": ";
if (!solve()) cout << "No" << '\n';
else cout << "Yes" << '\n';
}
return 0;
}
NC20583 [SDOI2016]齿轮的更多相关文章
- [Sdoi2016]齿轮
4602: [Sdoi2016]齿轮 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 613 Solved: 324 [Submit][Status ...
- BZOJ 4602: [Sdoi2016]齿轮 dfs
4602: [Sdoi2016]齿轮 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4602 Description 现有一个传动系统,包 ...
- BZOJ4602 Sdoi2016 齿轮 【带权并查集】*
BZOJ4602 Sdoi2016 齿轮 Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组 ...
- bzoj 4602: [Sdoi2016]齿轮
4602: [Sdoi2016]齿轮 Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组合 ...
- BZOJ4602:[SDOI2016]齿轮(并查集)
Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v ...
- 【bzoj4602】[Sdoi2016]齿轮 BFS
题目描述 给出一张n个点m条边的有向图,每条边 (u,v,x,y) 描述了 u 的点权乘 x 等于 v 的点权乘 y (点权可以为负).问:是否存在满足条件的图. 输入 有多组数据,第一行给定整数T, ...
- BZOJ4602 SDOI2016齿轮(搜索)
dfs一遍给每个齿轮随便标个值看是否矛盾就行了. #include<iostream> #include<cstdio> #include<cmath> #incl ...
- bzoj4602 [Sdoi2016]齿轮
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4602 [题解] 对于每组齿轮(u, v)连边,权值为y/x(反向边x/y) 那么直接dfs计 ...
- [bzoj4602][Sdoi2016]齿轮——dfs
题目 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x : y.即如果只考虑这两个组合齿轮,编号为u的齿轮转动x圈,编号为v的齿轮会转动y圈.传 ...
随机推荐
- [AcWing 35] 反转链表
迭代版本 点击查看代码 /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next ...
- python数据可视化-matplotlib入门(6)-从文件中加载数据
前几篇都是手动录入或随机函数产生的数据.实际有许多类型的文件,以及许多方法,用它们从文件中提取数据来图形化. 比如之前python基础(12)介绍打开文件的方式,可直接读取文件中的数据,扩大了我们的数 ...
- C#开发PACS医学影像三维重建(十三):基于人体CT值从皮肤渐变到骨骼的梯度透明思路
当我们将CT切片重建为三维体之后,通常会消除一些不必要的外部组织来观察内部病灶, 一般思路是根据人体常见CT值范围来使得部分组织透明来达到效果, 但这是非黑即白的,即,要么显示皮肤,要么显示神经,要么 ...
- git clone指定分支
技术背景 Git是代码版本最常用的管理工具,此前也写过一篇介绍Git的基本使用的博客,而本文介绍一个可能在特定场景下能够用到的功能--直接拉取指定分支的内容. Git Clone 首先看一下如果我们按 ...
- 806. Number of Lines To Write String - LeetCode
Question 806. Number of Lines To Write String Solution 思路:注意一点,如果a长度为4,当前行已经用了98个单元,要另起一行. Java实现: p ...
- elementUI 输入框用户名和密码取消自动填充
<!-- 用户名取消自动填充 autocomplete="off" --> <el-form-item label="用户名" prop=&q ...
- 且看这个Node全栈框架,实现了个Cli终端引擎,可无限扩充命令集
背景介绍 一般而言,大多数框架都会提供Cli终端工具,用于通过命令行执行一些工具类脚本 CabloyJS提供的Cli终端工具却与众不同.更确切的说,CabloyJS提供的是Cli终端引擎,由一套Cli ...
- CabloyJS微信模块、企业微信模块已出齐
前言 当Cabloy-企业微信模块完成时,加上之前已完成的Cabloy-微信模块,关于在CabloyJS中与微信/企业微信对接的任务已经完成了.这些模块的目标就是,只需填入各类服务的参数,就可以直接进 ...
- 【实操干货】做好这 16 项优化,你的 Linux 操作系统焕然一新
大家好,这次跟大家谈谈又拍云的操作系统优化方案.往简单地说,我们使用的 Linux 操作系统主要都是基于 CentOS6/7 的精简和优化.往复杂地说,则是我们有两套系统,业务上使用的定制 Linux ...
- VBA驱动SAP GUI实现办公自动化(一)
小爬之前写过一系列Python驱动SAP GUI实现办公自动化的文章,其实如果我们的实际业务不是太复杂,且我们对VBA语法比较熟悉的话,我们完全可以借助Excel VBA来驱动SAP GUI做很多自动 ...