2017暑假訓練之並查集
阿新 • • 發佈:2019-01-11
開學了,事情也越來越多了。我會努力補完的。
並查集基礎應用
HDUOJ 1232 暢通工程
HDUOJ 1272 小希的迷宮
POJ 1182 食物鏈
向量偏移做法,並查集程式碼真的清晰美好哇!
HDUOJ 3038 How Many Answers Are Wrong
並查集基礎應用
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; //尋找root while (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;
}