演算法6-8~6-11:用樹表示的等價問題 (c語言)
阿新 • • 發佈:2018-11-29
題目描述
在離散數學中,對等價關係和等價類的定義是:
如果集合S中的關係R是自反的、對稱的和傳遞的,則稱它為一個等價關係。
等價關係是現實世界中廣泛存在的一種關係,許多應用問題可以歸結至等價類問題,這類問題通常被稱為等價問題。
通過使用集合,能夠解決等價問題。而集合可以通過雙親表示法的樹結構進行儲存。通過對樹結構的操作,可以實現查詢、歸併等操作。查詢操作和歸併操作的演算法如下:
在以上的歸併操作中,由於表示集合的樹的深度與樹形成的過程有關,因此在最壞情況下全部歸併操作將會有O(n2)的複雜度。而通過在歸併時比較子集所含成員的數目,令成員少的歸併至成員多的集合,將能夠提高演算法的效率。下面給出優化的歸併操作演算法:
另外,通過增加“壓縮路徑”的功能,即將所有從根到相應元素路徑上的元素都變成樹根的孩子。演算法如下所示:
本題中,將會給出n個原本互不相交的集合及k次集合合併的操作。通過這k次合併,判斷最終的某兩個原始的集合是否被合併成了同一個集合。
輸入描述
輸入的第一行包含兩個用空格隔開的正整數n和k,其中n不超過100,k不超過n-1。
之後的k行中,每行包含兩個用空格隔開的正整數x和y,表示將x元素所在的集合和y元素所在的集合合併至同一個集合。保證x和y均在1至n之間。
最後一行中,包含兩個正整數,表示需要判斷是否在同一個集合的元素編號。
輸出描述
共一行,包含字串“YES”或“NO”,“YES”表示需判斷的元素在同一個集合中,“NO”表示不在同一個集合中。請注意不需要輸出引號,且行尾輸出換行。
輸入樣例
5 2
1 3
2 3
1 2
輸出樣例
YES
/*這題就是將每個元素的集合的根節點設為自己,然後在將題目給出的元素根節點進行合併,最後找題目要求的兩個元素集合根節點是否相同 #include<stdio.h> #include<string.h> #include<stdlib.h> int t[105]; int find(int a) //並查集查詢根節點,並且吧路徑上所有結點的根節點都變為同一個 { int r = a; while(t[r] != r) { r = t[r]; } int i = a, j; while(i != r) { j = t[i]; t[i]= r; i = j; } return r; } void Union(int a, int b) //根節點合併 { int x = find(a); int y = find(b); if(a != b) { t[a] = b; } } int main() { int n, m, i, j, a, b, x, y; while(~scanf("%d %d", &n, &m)) { for(i = 1; i <= n; i++) { t[i] = i; } for(i = 0; i < m ; i++) { scanf("%d %d", &a, &b); Union(a, b); } scanf("%d %d", &x, &y); if(find(x) != find(y)) { printf("NO\n"); } else { printf("YES\n"); } } return 0; }