等式
描述
有n个变量和m个“相等”或“不相等”的约束条件,请你判定是否存在一种赋值方案满足所有m个约束条件。
输入
第一行一个整数T,表示数据组数。
接下来会有T组数据,对于每组数据:
第一行是两个整数n,m,表示变量个数和约束条件的个数。
接下来m行,每行三个整数a,b,e,表示第a个变量和第b个变量的关系:
若e=0则表示第a个变量不等于第b个变量;
若e=1则表示第a个变量等于第b个变量
输出
输出T行,第i行表示第i组数据的答案。若第i组数据存在一种方案则输出"Yes";否则输出"No"(不包括引号)。
输入样例1
2
5 5
1 2 1
2 3 1
3 4 1
1 4 1
2 5 0
3 3
1 2 1
2 3 1
1 3 0
输出样例1
Yes
No
#include <bits/stdC++.h>
using namespace std;
const int len = 300005;
//rankl 判断集合归并到哪家(即 低的一家的父亲节点 认 高的一家父亲节点做父亲节点)
//father 用于父亲节点的记录
int rankl[len];
int father[len];
//find父亲节点
int find(int x){
//如果father[x] == x则x的父亲节点就是自己(即没有父亲节点)
//否则继续查找 自己的父亲节点
return father[x] == x?x:father[x] = find(father[x]);
}
//判断 得出 结论
string getAnswer(int m, int n, vector<int> A, vector<int> B, vector<int> E){
for(int i = 1;i <= n;i++){
//初始化 一开始 父亲节点都是 自己
//一开始各个集合的 秩都是 0
father[i] = i;
rankl[i] = 0;
}
//E = 1提前
int cnt = 0;
for(int i=0; i<m; ++i) //将e=1的操作提到e=0的操作前
if(E[i] == 1) {
swap(E[i], E[cnt]);
swap(A[i], A[cnt]);
swap(B[i], B[cnt]);
++cnt;
}
// 循环条件
for(int i = 0;i < m;i++){
//找出A[i] 与 B[i]的最高父亲节点
int setA = find(A[i]);
int setB = find(B[i]);
// 如果E[i] = 0 判断 如果 A[i] 和 B[i]的父亲节点相同说明 两个在一个集合中 则 此条件错误
if(E[i] == 0){
if(setA == setB)
return "No";
}
else{
//判断 谁的秩高 低的集合的父亲节点认高的集合的父亲节点做父节点
if(rankl[setA] < rankl[setB])
father[setA] = setB;
else{
father[setB] = setA;
// 如果 两个节点父亲节点的秩的大小相同 则默认让 A[i] 做父亲节点
if(setA == setB)
rankl[setA] += 1;//相同时认A[i]做父亲的节点 其秩 + 1
}
}
}
return "Yes";
}
int main(int argc, char const *argv[]){
//A B 代表元素 E代表操作
vector<int> A;
vector<int> B;
vector<int> E;
//m代表判断条件的数量
//n代表元素数量
int m,n;
scanf("%d%d",&m,&n);
for(int i = 0;i < m;i++){
int ai,bi,ci;
scanf("%d%d%d",&ai,&bi,&ci);
A.push_back(ai);
B.push_back(bi);
E.push_back(ci);
}
cout << getAnswer(m,n,A,B,E);
return 0;
}