poj 2492(並查集),poj2492
題意:有一個科學家提出了一個假設,一種蟲子只有異性戀,而不是同性戀,然後開始實驗來驗證猜想,給出了n個蟲子,編號從1到n,給出了q組戀愛蟲子的編號,問是否驗證猜想。
題解:數組倍增,給每個蟲子一個異性戀的對象集合,然後每次輸入的兩個蟲子如果不在同一個集合內,就放到對方異性戀集合內,否則無法驗證猜想。
#include <stdio.h>const int N = 4005;int n, q, pa[N];int get_parent(int x) { return x == pa[x] ? x : pa[x] = get_parent(pa[x]);}int main() { int t, cas = 1; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &q); int nn = 2 * n; for (int i = 1; i <= nn; i++) pa[i] = i; int flag = 0; while (q--) { int a, b; scanf("%d%d", &a, &b); int px = get_parent(a); int py = get_parent(b); if (px == py) flag = 1; else { int t1 = get_parent(a + n); int t2 = get_parent(b + n); pa[px] = t2; pa[py] = t1; } } if (cas > 1) printf("\n"); printf("Scenario #%d:\n", cas++); if (flag) printf("Suspicious bugs found!\n"); else printf("No suspicious bugs found!\n"); } return 0;}
另一種做法,帶權並查集,加一個數組rel[i]表示i和父節點是否是同性,尋找根節點時更新rel[i],如果發現輸入的兩個蟲子是同一個根節點且與根節點關係相同,這兩個蟲子是同性戀,否則放到一個集合內,並更新其中一個蟲子的根節點的rel。
#include <stdio.h>const int N = 4005;int n, q, pa[N], rel[N];int get_parent(int x, int &r) { int temp = x; r = 1; while (x != pa[x]) { if (rel[x] == 0) r = !r; x = pa[x]; } pa[temp] = x; rel[temp] = r; return pa[x];}int main() { int t, cas = 1; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &q); for (int i = 1; i <= n; i++) { pa[i] = i; rel[i] = 1; } int flag = 0; while (q--) { int a, b, r1, r2; scanf("%d%d", &a, &b); int px = get_parent(a, r1); int py = get_parent(b, r2); if (px == py && r1 == r2) flag = 1; else { pa[py] = px; rel[py] = r1 == r2 ? 0 : 1; } } if (cas > 1) printf("\n"); printf("Scenario #%d:\n", cas++); if (flag) printf("Suspicious bugs found!\n"); else printf("No suspicious bugs found!\n"); } return 0;}