1. 程式人生 > >算法訓練營:等式

算法訓練營:等式

實現 fin 變量 限制 是否 初始 返回 ace esp

題目:

描述

有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

樣例1解釋

一共有2組數據。

對於第一組數據,有5個約束:

  • 變量1=變量2
  • 變量2=變量3
  • 變量3=變量4
  • 變量1=變量4
  • 變量2≠變量5

顯然我們可以令:

  • 變量1=變量2=變量3=變量4=任意一個數值
  • 變量5=任意一個和變量2不同的數值

故第一組數據輸出"Yes"。 對於第二組數據,有3個約束:

  • 變量1=變量2
  • 變量2=變量3
  • 變量1≠變量3

由前兩個約束可推出變量1=變量3,但第三個約束表明變量1≠變量3,矛盾。

故第二組數據輸出"No"。

限制

對於10%的數據,n,m ≤ 5,T ≤ 5;

對於50%的數據,n,m ≤ 1000,T ≤ 10;

對於100%的數據,1 ≤ n,m ≤ 500000,1 ≤ a,b ≤ n,T ≤ 100。

保證所有數據的n總和與m總和不超過500000。

時間:2 sec

空間:256 MB

提示

用並查集來維護相等的集合。

代碼實現

#include <iostream>
#include <vector>
using namespace std;

// ================= 代碼實現開始 =================

const int N = 300005 ;

//Father : 每個節點的父親節點
//Rank : 節點的秩
int Father[N] , Rank[N] ;

//查找節點x所有集合的根 // x : 節點x 返回值 :根 int find( int x ){ return Father[x] == x ? x : Father[x] = find( Father[x] ) ; } // 給定n個變量以及m個約束,判定是否能找出一種賦值方案滿足這m個約束條件 // n:變量的個數 // m:約束條件的個數 // A:大小為m的數組,表示m條約束中的a // B:大小為m的數組,表示m條約束中的b // E:大小為m的數組,表示m條約束中的e // 返回值:若能找出一種方案,返回"Yes";否則返回"No"(不包括引號)。 string getAnswer(int n, int m, vector<int> A, vector<int> B, vector<int> E) { //初始化 for( int i = 1 ; i <= n ; i++ ) { Father[i] = i ; Rank[i] = 0 ; //各個節點的秩起初都是0 } // 將 e = 1 都放到 e = 0 前面 int cnt = 0 ; for( int i = 0 ; i < m ; i++ ) { 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++ ) { int setA = find( A[i] ) ; //找到A[i]所有集合的根 int setB = find( B[i] ) ; //找到B[i]所有集合的根 if( E[i] == 0 ) { if( setA == setB ) return "No" ; } else{ if( setA != setB ) { if( Rank[setA] > Rank[setB] ) swap( setA , setB ) ; //RankB 的父節點更高 Father[setA] = setB ; if( Rank[setA] == Rank[setB] ) Rank[setB] ++ ; } } } return "Yes"; } // ================= 代碼實現結束 ================= int main() { int T; for (scanf("%d", &T); T--; ) { int n, m; scanf("%d%d", &n, &m); vector<int> A, B, E; for (int i = 0; i < m; ++i) { int a, b, e; scanf("%d%d%d", &a, &b, &e); A.push_back(a); B.push_back(b); E.push_back(e); } printf("%s\n", getAnswer(n, m, A, B, E).c_str()); } return 0; }

算法訓練營:等式