[SDOI2016]齿轮

链接:https://ac.nowcoder.com/acm/contest/23156/1009
来源:牛客网
 

题目描述

现有一个传动系统,包含了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。

题意:

有n个齿轮组合被m个链条连接, 当齿轮x转u圈齿轮y会转v圈,求这些齿轮能不能同时转动(就是看有没有冲突)。

题解:

这个题的解法是带权并查集,因为我们知道齿轮a、b的关系和b、c的关系,那么也就知道了a、c的关系,用y / x 表示其传动比z,意思是齿轮a转一圈b会转几圈

用一个数组parent存根节点,另一个数组w存与根节点的传动比,传动比可在find中更新。假设已知a、b和b、c的传动比x和y,那么a、c的传动比为x*y。

如果a、b不在一个集合内,则合并,w[find(a)] = w[b] / w[a] * z(z为a、b的传动比),求出a的根节点与b的根节点之间的传动比,这个式子的意思是b与其根节点传动比与a与其根节点传动比之比乘a、b的传动比,如果不清楚怎么来的可以自己举个例子。

如果a、b已在一个集合内,直接将他们的传动比与输入传动比进行比较就行了,a、b传动比为w[find(b)] /w[find(a)],这个还是很容易得到,然后因为是double,要缩小一下精度范围

#include<bits/stdc++.h>
using namespace std;
#define quick ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
#define FOR(it, a) for(auto &it : a) 
#define forn(i, begin, end) for (int i = (begin); i < (end); ++i)
#define fore(i, begin, end) for (int i = (begin); i <= (end); ++i)
#define rofn(i, begin, end) for (int i = (begin); i > (end); --i)
#define rofe(i, begin, end) for (int i = (begin); i >= (end); --i)
#define pb push_back
#define ppb pop_back()
#define pf push_front
#define ppf pop_front()
#define eb emplace_back
#define x first
#define y second
#define please 0
#define AC return
#define endl '\n'
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<long long, long long > PLL;
typedef pair<double, double> PDD;
typedef pair<int, int> PIS;
typedef pair<int, int> PSI;
typedef pair<int, char> PIC;
typedef pair<char, int> PCI;
typedef pair<long long, int> PLS;
typedef pair<int, long long> PSL;
typedef vector<char> VCHAR;
typedef vector<vector<char> > VVCHAR;
typedef vector<int> VINT;
typedef vector<vector<int> > VVINT;
typedef vector<long long> VLL;
typedef vector<vector<long long> > VVLL;
typedef vector<double> VDOUBLE;
typedef vector<vector<double> > VVDOUBLE;
template<class T>
ostream & operator<<(ostream &out, vector<T> &a) { for (T &i : a) cout << i << ' '; return out; }
template<class T>
ostream & operator<<(ostream &out, vector<vector<T> > &a) { for (vector<T> &i : a) cout << i << endl; return out; }
const LL INF = 1e18;
const int N = 100010;
const LL mod = 1e9 + 7;
const double eps = 1e-6;
/****************

****************/

int n, m;

map<int, int> parent;
map<int, double> w;

int find(int x) {
	if(parent[x] != x) {
		int t = parent[x];
		parent[x] = find(parent[x]);
		w[x] *= w[t];
	}
	return parent[x];
}

bool merge(int x, int y, double z) {
	int xx = find(x);
	int yy = find(y);
	if(xx == yy) return abs(w[y] / w[x] - z) < eps;
	parent[yy] = xx;
	w[yy] = 1 / w[y] * z * w[x];
	return true;
}

int cas = 1;

void slove() {
	cout << "Case #" << cas++ << ": " ;
	cin >> n >> m;
	bool flag = true;
	fore(i, 1, n) parent[i] = i, w[i] = 1;
	forn(i, 0, m) {
		int x, y, u, v;
		cin >> x >> y >> u >> v;
		if(!merge(x, y, double(1.0 * v / u))) {
			flag = false;
		}
	}
	if(flag) cout << "Yes" << endl;
	else cout << "No" << endl;
}


int main() {
	quick;
	int t = 1; cin >> t;
	while (t--) {
		slove();
	} 
	cout.flush();
    system("pause");
	AC please;
}
/*******************************************
				  坤坤助我
............................................
............................................
............................................
............................................
.............................1ffLf1.........
............................GGGGGGGC........
....................8CCCftCCCCC1;LLG,.......
..................:CC8CCC.CCCCCCii..........
.................CC88CCCC.CCCCCCC...........
................CC88CCCCC .8.:8CCC..........
................888 CCCCC.88888G;;,.........
,................888CC88.888888888,.........
:::...............CCC888.888888888..........
:::::............Gi1tC8f888888C88,..........
:::::::,........111tttfffffLG8888...........
:::::::::,....ii111ttttttfffttG.............
::::::::::::i111tttffffffffffttt............
::::::::::11tttttfff....fffffftt ...........
..:::::::1Lf1tff,..........fffff1...........
....,:::iiftG::::::.........,LLGtL..........
::::::;:i11t:;;;;;;::,,,,,,,,, f1ii,::,,,,,,
::::::::i11t:::::::::::::::::::f111:::::::::
::::::::111:::::::::::::::::::::t111::::::::
:::::::i1if::::::,,,,,,,,,,,,,,:i111::::::,:
,,,,,::,8G,,,,,,,,,,,,,,,,,,,,,,,tL1:,,,,,,,
,,,,,,:LGL;,,,,,,,,,,,,,,,,,,,,,,,CLf,,,,,,,
,,,,,;LGGG,,,,:,,,,,,,,,,,,,,,,,,,LGCG,,,,,,

*******************************************/

本菜鸡被学长逼着写这些实在太累了,幸好这周刚好学带权并查集刷到这题,不然都不知道写什么

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值