思路:設r(x)表示節點x與根結點的關係,px表示x的根結點。記錄每個節點與其父節點的關係,就能很方便知道每個節點以及和它的父節點的關係。
struct nodea[maxn];
//關係:0表示同類, 1表示父節點吃子節點, 2表示子節點吃父節點
現在給定節點x和y,它們的關係是rel,如何判斷這句話是真還是假?
利用find函式找到它們的根結點px和py,以及它們和各自根結點的關係r(x)和r(y),如果px!=py說明x和y沒有位於同一集合,那麼這句話不會和任何話發生衝突,即這一定是真話,然後合併兩個集合;另一種情況就是px==py,說明x和y位於同一集合,現在已經得到x(x)和r(y),那麼如何知道x和y的關係呢?我先介紹一下find函式的實現:
int find(int x, int &r)
int y = find(a[x].par, r);
a[x].par = r; //路徑壓縮
return a[x].rel = (a[x].rel + y) % 3;
}
find函式每次返回當前節點與根結點的關係,那麼在已知當前節點和它的父親節點關係,父親節點和根結點的關係,很容易得到當前節點與跟節點的關係r(x) = ( r(a[x].par) + a[x].rel) % 3。
同樣對於上面的問題,只需要變換一下x、root、y三者的關係,也能求得x和y的關係r(x, y),如果r(x, y) == rel,說明是真話,否則假話。
注意:所有的關係轉換都利用了find函式中的思想,請保證明確關係轉換才能看懂unionset函式。
ac**
#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
#pragma comment(linker, "/stack:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define pi pairtypedef long long ll;
const int maxn = 50000 + 5;
struct nodea[maxn];
//關係:0表示同類, 1表示父節點吃子節點, 2表示子節點吃父節點
int find(int x, int &r)
int y = find(a[x].par, r);
a[x].par = r; //路徑壓縮
return a[x].rel = (a[x].rel + y) % 3;
}bool unionset(int x, int y, int rel)
else
} int main()
int d, x, y, ans = 0;
for(int i = 0; i < k; ++i)
if(!unionset(x, y, d-1)) ans++;
} printf("%d\n", ans);
break; //只有一組資料
} return 0;
}
如有不當之處歡迎指出!
poj1182 食物鏈(經典並查集)
題意 中文題 思路 最詳細的題解 include include include include include include include include include include include include include using namespace std define ma...
POJ 1182 食物鏈 經典並查集
食物鏈 time limit 1000ms memory limit 10000k total submissions 57770 accepted 16890 description 動物王國中有三類動物a,b,c,這三類動物的食物鏈構成了有趣的環形。a吃b,b吃c,c吃a。現有n個動物,以1 n...
poj 1182 食物鏈 經典並查集
題意 題目不難看懂,但是做起來感覺很複雜。思路 種類並查集的應用,其中關鍵的幾個公式推導感覺不是很好理解,以後回頭看也許會有收穫。include include includeusing namespace std int p 50010 r 50010 int n,k,co int find in...