A Bug‘s life POJ 2492 解題報告 (種類並查集)
阿新 • • 發佈:2019-01-27
這也算是種類並查集的一道經典例題了吧,題意就不多解釋了,先寫一些我對種類並查集的一些理解。
種類並查集比普通的並查集多一個relation陣列,relation[i] 記錄了 i 和 其直接父親節點的關係,這個關係的表示因題目而異,種類並查集的重點和難點就是對這個relation陣列的維護。種類
在這個題中,relation陣列具體表示是:以0表示和父親節點的性別相同,1表示和父親節點的性別不同。初始時可設初值全部為0。在Find函式中進行路徑壓縮時,要注意同時維護relation陣列,如果relation[i] 和 relation[ father[i] ] 的值相同( 此時relation[ father[i] ] 實際上表示的是 i 的 父親節點與 i 的祖先節點之間的關係)
在Union函式進行合併中,首先看看x 和 y是否在同一個集合中。如果在同一個集合中,那麼再判斷他們相較於祖先節點的關係,如果關係相同說明是同性戀。如果不在同一個集合裡,就可以合併。合併之後要繼續考慮這時relation陣列的變化。在我們尋找變化規律之前,讓我們再仔細的看看relation陣列,如果你和我一樣看過很多人的題解(汗……)你會發現很多人使用Rank陣列來表示relation,其實這也是relation陣列的本質,relation陣列其實表示的正是節點的偏移量,
也正是如此,種類並查集其實是帶偏移量的並查集。
下面上一波C艹實現
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 2500; int fa[MAXN], relation[MAXN]; bool flag; void Init(int n){ for(int i = 0;i <= n;++i){ fa[i] = i; relation[i] = 0; } } int Find(int x){ if(fa[x] == x) return x; int temp = Find(fa[x]); relation[x] = (relation[x] + relation[fa[x]] ) % 2; fa[x] = temp; return temp; } void Union(int x, int y){ int faX = Find(x), faY = Find(y); if(faX == faY){ if(relation[x] == relation[y]){ flag = true; return; } } fa[faX] = faY; relation[faX] = (relation[x] - relation[y] + 1 ) % 2; // 這裡的+1其實可以認為是當faX連入faY時,x相對於faY的偏移量又加一。 } int main() { //freopen("input.txt", "r", stdin); int T; scanf("%d", &T); for(int i = 1;i <= T;++i){ int n, k; flag = false; scanf("%d %d",&n, &k); Init(n); for(int i = 0;i < k;++i){ int a, b; scanf("%d %d",&a, &b); if(flag) continue; Union(a, b); } printf("Scenario #%d:\n",i); if(flag) printf("Suspicious bugs found!\n"); else printf("No suspicious bugs found!\n"); printf("\n"); } return 0; }