使用並查集來維護不同的類關系
阿新 • • 發佈:2018-07-13
祖先 特殊 當前 () str -- 節點 數據結構 const
我們理解並查集這個數據結構的時候不要過於死板,我們要知道
並查集是用來維護關系的,而不是單純一味去歸並,歸並,歸並
下面給出一個問題嘗試用並查集來解決:一共有兩個類,然後告訴你若幹組數據,每一組數據的兩個元素不是一類的,然後在線判斷兩個元素是否是同一類
這個時候如果你只會歸並就行不通的,還需要一些特殊的處理
我們需要在並查集的那個數組的基礎之上,需要另一個數組來記錄這種特殊的現象
int set[maxn],a[maxn]; //a表示這個節點和父節點的關系,0表示相同1表示不同
接下來我們的路徑壓縮加找祖宗函數也需要相應的調整,要不斷更新a的值才行
int find(int x) {if (x==set[x]) return x; //x的父節點是祖先節點的情況,不需要改變a的值 int t=find(set[x]); a[x]=(a[set[x]]+a[x])%2; //判斷歸並之後x和祖先的團夥關系 return set[x]=t; }
歸並的時候還是很簡單的,但是也要同時去更新a的值
void Union(int x, int y) { int fx=find(x); int fy=find(y); set[fx]=fy; //根據x和y不同確定x和x的祖先節點的同夥關系 if (a[y]==0) a[fx]=1-a[x]; else a[fx]=a[x]; }
我們在判斷的時候,已知的情況都已經歸並到一棵樹裏面,並且有a數組記錄已知情況下所有元素的關系,直接判斷即可
fx=find(x); fy=find(y); if (fx!=fy) printf("Not sure yet.\n"); else if(a[x]==a[y]) printf("In the same gang.\n"); else printf("In different gangs.\n");
接下來我們給出完整的實現,這道題的大意是這樣的,有兩個犯罪團夥,然後告訴你若幹個關系,關系是兩個犯人不是一個團夥的,然後在線判斷給定的兩個犯人之間的關系
1 //一共有兩類,給定某兩個元素之間的不同類關系 2 //判斷當前給定情況下某兩個元素是否同類 3 #include<iostream> 4 #include <cstdio> 5 #include <cstring> 6 using namespace std; 7 const int maxn=100005; 8 int t,n,m; 9 int fx,fy,x,y; 10 char c; 11 int set[maxn],a[maxn]; 12 //a表示這個節點和父節點的關系,0表示相同1表示不同 13 int find(int x) 14 { 15 if (x==set[x]) return x; 16 //x的父節點是祖先節點的情況,不需要改變a的值 17 int t=find(set[x]); 18 a[x]=(a[set[x]]+a[x])%2; 19 //判斷歸並之後x和祖先的團夥關系 20 return set[x]=t; 21 } 22 void Union(int x, int y) 23 { 24 int fx=find(x); 25 int fy=find(y); 26 set[fx]=fy; 27 //根據x和y不同確定x和x的祖先節點的同夥關系 28 if (a[y]==0) 29 a[fx]=1-a[x]; 30 else 31 a[fx]=a[x]; 32 } 33 int main() 34 { 35 36 cin>>t; 37 while (t--) 38 { 39 cin>>n>>m; 40 for (int i=1; i<=n; i++) 41 { 42 set[i] = i; 43 a[i] = 0; 44 } 45 while(m--) 46 { 47 cin>>c>>x>>y; 48 if (c==‘A‘) 49 { 50 fx=find(x); 51 fy=find(y); 52 if (fx!=fy) 53 printf("Not sure yet.\n"); 54 else if(a[x]==a[y]) 55 printf("In the same gang.\n"); 56 else 57 printf("In different gangs.\n"); 58 } 59 else 60 Union(x, y); 61 } 62 } 63 return 0; 64 }
使用並查集來維護不同的類關系