并查集,比较简单的数据结构,二叉树的一种变形,可以执行1.查询是否在同一集合操作 ,2.合并两个集合操作, 所有数字组成了若干棵树,每棵树上的成员代表着一个集合,每棵树都有着唯一的顶部, 也就是说每一个成员都只存在一棵树上面并且可以用这颗树上的唯一的顶点代表他所在的集合。当执行查询操作的时候,只需要判断两个数所在树的顶点是否相同;当执行合并操作时候,只需将其中一棵树的顶点变成另一颗树顶点的子叶。 为了降低复杂度这里采用两个技巧,1.每棵树从顶点到任意一个数需要经过的最大子叶数目叫做这个棵树的深度u,明显,如果深度越大,由一个数得到他所在树的顶点需要的时间也就越多,而只要在一棵树上就能代表在一个集合,那么谁与谁的位置就无所谓了,那么可以令一个子叶的父亲等于这个子叶的父亲的父亲,即fat[i] = fat[fat[i]], fat代表的是一个子叶的父亲(如果i和fat[i]不是顶点的话) 2.执行合并操作的时候将深度较小的那棵树插入到深度较大的那棵树,如果深度相同,那么被插入的那棵树深度加一。
这里有一道并查集例题:http://poj.org/problem?id=1182,原题是中文描述,直接上网站
答案直接上代码和注释
//#include <bits/stdc++.h>//poj不支持此头文件 #include <iostream> #include <cstring> #include <cstdio> using namespace std; #define maxn 200005 int ans, n, k; int fat[maxn];///i -> A, i + N * 1 -> B, i + N * 2 -> C; int deep[maxn]; int Find(int x)//查询操作,获得一个数所在树的顶点,顶点的父亲就是他自己 { if(fat[x] == x)return x; return x = Find(fat[x]); } void getlink(int a1, int b1)//合并操作,传入的值是两棵树的顶点 { if(deep[a1] < deep[b1]) fat[a1] = b1; else { fat[b1] = a1; if(deep[a1] == deep[b1]) deep[a1]++; } } bool funA(int x, int y) { if(x > n || y > n || x < 1 || y < 1) return false; int a1 = Find(x), a2 = Find(x + n), a3 = Find(x + 2*n); int b1 = Find(y), b2 = Find(y + n), b3 = Find(y + 2*n); if(a1 == b2 || a1 == b3 || a2 == b1 || a2 == b3 || a3 == b1 || a3 == b2) return false; getlink(a1, b1); getlink(a2, b2); getlink(a3, b3); return true; } bool funB(int x, int y) { if(x > n || y > n || x < 1 || y < 1) return false; if(x == y) return false; int a1 = Find(x), a2 = Find(x + n), a3 = Find(x + 2*n); int b1 = Find(y), b2 = Find(y + n), b3 = Find(y + 2*n); if(a1 == b1 || a2 == b2 || a3 == b3 || a1 == b3 || a2 == b1 || a3 == b2)///与之前所描述的矛盾 return false; getlink(a1, b2); getlink(a2, b3); getlink(a3, b1); return true; } int main() { ans = 0; cin >> n >> k; for(int i = 0; i < 3; i++)//i代表的是i属于集合A, i + n代表的是i属于集合B, i + 2*n代表的是i属于集合C, 在这个并查集里面,每一棵树代表的是这棵树上所有的成员都成立或者都不成立 { //cout<<"=="<<endl; for(int j = 1; j <= n; j++) fat[j + i * n] = j + i * n;///make tree } for(int i = 0; i < k; i++) { int d, x, y; scanf("%d%d%d", &d, &x, &y); if(d == 1) { if(!funA(x, y)) ans++; } else if(d == 2) if(!funB(x, y)) ans++; } cout<<ans<<endl; }