並查集的實現 POJ-1182
阿新 • • 發佈:2018-11-16
//Problem地址:http://poj.org/problem?id=1182 using namespace std; const int maxn = 50000 + 5; const int maxk = 100000 + 5; long long n, k; int T[maxk], X[maxk], Y[maxk], par[maxn * 3], rankk[maxn * 3]; void init(int n) {//初始化n個元素,最開始沒有邊 for (int i = 0;i < n;i++) { par[i] = i;rankk[i] = 0; } } int find(int x) {//查詢樹的根 if (par[x] == x) return x;//par[x]的鍵為本節點編號 值為根節點編號 根節點的值和鍵相等 else return par[x] = find(par[x]);//查詢過程中向上經過的所有節點都改為直接連向根(路徑壓縮) } void unite(int x, int y) {//合併x和y所屬的集合 x = find(x);y = find(y); if (x == y) return;//若x,y的根節點相同,則直接返回 if (rankk[x] > rankk[y]) par[y] = x; //x賦值給par[y] 表示讓x作為y的根節點 從根y向根x連邊 else { par[x] = y; if (rankk[x] == rankk[y])rankk[y]++; } } bool same(int x, int y) {//判斷x,y是否屬於一個集合 return find(x) == find(y); } //實現並查集 //解決題目 void solve() { int ans = 0; for (int i = 0;i < k;i++) { int t = T[i];int x = X[i] - 1;int y = Y[i] - 1; if (x < 0 || x >= n || y < 0 || y >= n) { ans++;continue; } if (t == 1) { if (same(x, y + n) || same(x, y + 2 * n)) ans++; else { unite(x, y);unite(x + n, y + n);unite(x + 2 * n, y + 2 * n);//同類動物歸於一個根下 } } else { if (same(x, y) || same(x, y + 2 * n)) ans++; else { unite(x, y + n);unite(x + n, y + 2 * n);unite(x + 2 * n, y); } } } printf("%d\n", ans); } int main() { //freopen("datain.txt", "r", stdin); while (~scanf("%lld%lld", &n, &k)) { if (n == 0 || k == 0)break; init(n * 3); for (int i = 0;i < k;i++) { scanf("%d%d%d", &T[i], &X[i], &Y[i]); } solve(); } }