2017暑假训练之并查集

来源:互联网 发布:淘宝联盟 旧版 编辑:程序博客网 时间:2024/05/17 22:53
开学了,事情也越来越多了。我会努力补完的。
并查集基础应用
HDUOJ 1232 畅通工程
int f[maxn], _rank[maxn];void init(int n) {for (int i = 1; i <= n; ++i) f[i] = i, _rank[i] = 0;}//路径压缩的递归及非递归写法int find(int a) {//return f[a] == a ? a : f[a] = find(f[a]);int root = a;//寻找rootwhile (f[root] != root) root = f[root];int cur = a;//改变f[cur]while (cur != root) {int temp = f[cur];f[cur] = root;cur = temp;}return f[a];}//按秩归并void _union(int a, int b) {int fa = find(a), fb = find(b);if (fa == fb) return;if(_rank[fa] < _rank[fb]) f[fa] = fb;else {f[fb] = fa;if (_rank[fa] == _rank[fb]) _rank[fa]++;}}int main() {int n, m;while (scanf("%d", &n) && n) {init(n);scanf("%d", &m);while (m--) {int a, b;scanf("%d%d", &a, &b);_union(a, b);}int ans = 0;for (int i = 1; i <= n; ++i) if (f[i] == i) ans++;printf("%d\n", ans - 1);}return 0;}
并查集的基础应用,蛮细节的一道题
HDUOJ 1272 小希的迷宫
int f[maxn]; vector<int> vis;void init() {vis.clear();for (int i = 1; i <= 100000; ++i) f[i] = i;}int find(int n) {//return f[n] == n ? n : f[n] = find(f[n]);int root = n;while (root != f[root]) root = f[root];int cur = n;while (cur != root) {int temp = f[cur];f[cur] = root;cur = temp;}return f[n];}bool _union(int a, int b) {int fa = find(a), fb = find(b);if (fa == fb) return false;f[fa] = fb;return true;}int main() {int a, b;while (scanf("%d%d", &a, &b)) {if (a == -1 && b == -1) break;if (a == 0 && b == 0) {printf("Yes\n");continue;}init();_union(a, b);vis.push_back(a);vis.push_back(b);bool ok = true;while (scanf("%d%d", &a, &b) && a) {//printf("fa = %d, fb = %d\n", f[a], f[b]);if (!_union(a, b)) ok = false;vis.push_back(a);vis.push_back(b);}//sort(vis.begin(), vis.end());vis.resize(unique(vis.begin(), vis.end()) - vis.begin());if (ok) {int cnt = 0;for (int i = 0; i < vis.size(); ++i)if (f[vis[i]] == vis[i]) cnt++;if (cnt > 1) ok = false;}if (ok) printf("Yes\n");else printf("No\n");}return 0;}
经典带权并查集
POJ 1182 食物链
向量偏移做法,并查集代码真的清晰美好哇!
int f[maxn], rela[maxn];void init(int n) {for (int i = 1; i <= n; ++i) f[i] = i, rela[i] = 0;}int find(int a) {if (f[a] == a) return a;int t = f[a];f[a] = find(f[a]);rela[a] = (rela[a] + rela[t]) % 3;return f[a];}void _union(int a, int b, int re) {int fa = find(a), fb = find(b);f[fa] = fb;rela[fa] = ((re + rela[b] - rela[a]) % 3 + 3) % 3;}int main() {int n, k;scanf("%d%d", &n, &k);init(n);int op, a, b, cnt = 0;while (k--) {scanf("%d%d%d", &op, &a, &b);if (a > n || a < 1 || b > n || b < 1) ++cnt;else if (op == 1 && find(a) == find(b) && rela[a] != rela[b]) ++cnt;else if (op == 2 && find(a) == find(b) && ((rela[a] - rela[b])%3+3)%3 != 1) ++cnt;else _union(a, b, op - 1);}printf("%d\n", cnt);return 0;}
种类并查集的做法,也十分清晰
int f[3 * maxn];int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}void unite(int a, int b) {int fa = find(a), fb = find(b);if (fa == fb) return;f[fa] = fb;}void init(int n) {for (int i = 1; i <= 3 * n; ++i) f[i] = i;}int main() {int n, q;scanf("%d%d", &n, &q);init(n);int op, a, b, ans = 0;while (q--) {scanf("%d%d%d", &op, &a, &b);if (a < 1 || a > n || b < 1 || b > n) ans++;else if (op == 1) {if (find(a) == find(b + n) || find(a) == find(b + 2 * n)) ans++;else unite(a, b), unite(a + n, b + n), unite(a + 2 * n, b + 2 * n);}else if (op == 2) {if (find(a) == find(b) || find(a) == find(b + 2 * n)) ans++;else unite(a, b + n), unite(a + n, b + 2 * n), unite(a + 2 * n, b);}}printf("%d\n", ans);return 0;}
种类并查集的变式
HDUOJ 3038 How Many Answers Are Wrong
int f[maxn], res[maxn];void init(int n) {for (int i = 0; i <= n; ++i) f[i] = i, res[i] = 0;}int find(int x) {int t = f[x];if (t == x) return x;f[x] = find(t);res[x] = res[x] + res[t];return f[x];}void unite(int a, int b, int sum) {int la = find(a), lb = find(b);if (la < lb) f[lb] = la, res[lb] = res[a] + sum - res[b];else f[la] = lb, res[la] = res[b] - sum - res[a];}int main() {int n, q;while (~scanf("%d%d", &n, &q)) {init(n);int l, r, sum, ans = 0;while (q--) {scanf("%d%d%d", &l, &r, &sum); --l;if (find(l) == find(r) && res[r] - res[l] != sum) ans++;else unite(l, r, sum);}printf("%d\n", ans);}return 0;}
原创粉丝点击