kuangbin专题五:并查集
不想写实验,不想改paper,写点代码吧(;´д`)ゞ
思路:简单并查集。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3 + 5; int N, D; int p[maxn]; bool vis[maxn]; struct Pos{ int x, y; }pos[maxn]; int findP(int x){ return x == p[x] ? x : p[x] = findP(p[x]); } void Union(int x, int y){ int px = findP(x), py = findP(y); if(px != py) p[px] = py; } bool in_dis(int x, int y){ int dx = pos[x].x - pos[y].x; int dy = pos[x].y - pos[y].y; return dx*dx + dy*dy <= D*D; } void repair(int x){ for(int i = 1; i <= N; i++) if(vis[i] && in_dis(i, x)) Union(i, x); vis[x] = true; } int main(){ cin >> N >> D; for(int i = 1; i <= N; i++) p[i] = i; for(int i = 1; i <= N; i++) cin >> pos[i].x >> pos[i].y; char op; int u, v; while(cin >> op){ if(op == 'O'){ cin >> u; repair(u); } else{ cin >> u >> v; int pu = findP(u), pv = findP(v); cout << (pu == pv ? "SUCCESS" : "FAIL") << endl; } } return 0; }
思路:简单并查集。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 3e4 + 5; const int maxm = 505; int p[maxn]; inline int findP(int x){ return x == p[x] ? x : p[x] = findP(p[x]); } inline void Union(int x, int y){ int px = findP(x), py = findP(y); if(px != py) p[px] = py; } int main(){ int n, m; while(cin >> n >> m && (n + m > 0)){ for(int i = 0; i < n; i++) p[i] = i; int k, s1, s2; for(int i = 1; i <= m; i++){ cin >> k; if(k) cin >> s1; for(int j = 1; j < k; j++){ cin >> s2; Union(s1, s2); } } int res = 0; for(int i = 0; i < n; i++) if(findP(0) == findP(i)) res++; cout << res << endl; } return 0; }
思路:简单并查集。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3 + 5; const int maxm = 1e3 + 5; int p[maxn]; bool vis[maxn]; inline int findP(int x){ return x == p[x] ? x : p[x] = findP(p[x]); } inline void Union(int x, int y){ int px = findP(x), py = findP(y); if(px != py) p[px] = py; } int main(){ int T; cin >> T; while(T--){ int n, m; cin >> n >> m; for(int i = 1; i <= n; i++) p[i] = i; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= m; i++){ int x, y; cin >> x >> y; Union(x, y); } int res = 0; for(int i = 1; i <= n; i++){ int pi = findP(i); if(!vis[pi]){ vis[pi] = true; res++; } } cout << res << endl; } return 0; }
HDU3038 How Many Answers Are Wrong
思路:带权并查集。这题个人觉得模型比较难想到,我第一次接触到的时候被提醒了才想起来带权并查集。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 2e5 + 5; int p[maxn], w[maxn]; int findP(int x){ if(x != p[x]){ int px = p[x]; p[x] = findP(p[x]); w[x] += w[px]; } return p[x]; } int main(){ int n, m; while(scanf("%d%d", &n, &m) != EOF){ for(int i = 0; i <= n; i++) p[i] = i, w[i] = 0; int res = 0; while(m--){ int a, b, s; scanf("%d%d%d", &a, &b, &s); a--; int pa = findP(a), pb = findP(b); if(pa == pb){ if((w[a] - w[b]) != s) res++; } else{ p[pa] = pb; w[pa] = w[b] - w[a] + s; } } cout << res << endl; } return 0; }
思路:经典带权并查集问题了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 5e4 + 5; int p[maxn], w[maxn]; int findP(int x){ if(x != p[x]){ int px = p[x]; p[x] = findP(p[x]); w[x] = (w[x] + w[px]) % 3; } return p[x]; } int main(){ int n, m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) p[i] = i, w[i] = 0; int res = 0; while(m--){ int d, x, y; scanf("%d%d%d", &d, &x, &y); if (x > n || y > n) { res++; continue; } if (d == 2 && x == y) { res++; continue; } d--; int px = findP(x), py = findP(y); if (px == py && (w[y] - w[x] + 3) % 3 != d){ res++; } else { p[py] = px; w[py] = (w[x] + d - w[y] + 3) % 3; } } cout << res << endl; return 0; }
思路:这题的DP好烦,不想写了。
思路:贪心。从后向前,找最贵的物品卖。感觉和并查集关系不大。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 10005; int p[maxn], w[maxn]; struct Item{ int p, d; } item[maxn]; bool d_cmp(const Item& a, const Item& b) { return a.d < b.d; } struct p_cmp{ bool operator()(const Item &a, const Item &b){ return a.p < b.p; } }; int findP(int x){ if(x != p[x]){ int px = p[x]; p[x] = findP(p[x]); w[x] = (w[x] + w[px]) % 2; } return p[x]; } int main(){ int n; while(cin >> n){ for(int i = 0; i < n; i++) cin >> item[i].p >> item[i].d; sort(item, item + n, d_cmp); int res = 0; int last = item[n-1].d, ind = n-1; priority_queue<Item, vector<Item>, p_cmp> q; for(int i = last; i > 0; i--){ while(ind >= 0 && item[ind].d >= i){ q.push(item[ind]); ind--; } if(q.size()){ Item itm = q.top(); q.pop(); res += itm.p; } } cout << res << endl; } return 0; }
思路:带权并查集。用以前的代码了。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 10005; int p[maxn], w[maxn], f[maxn]; struct Node{ int l, r; char s[5]; } q[maxn]; int findP(int x){ if(x != p[x]){ int px = p[x]; p[x] = findP(p[x]); w[x] ^= w[px]; } return p[x]; } int main(){ int n, m, k = 0; cin >> n >> m; for(int i = 1; i <= m; i++){ cin >> q[i].l >> q[i].r >> q[i].s; q[i].l--; f[++k] = q[i].l, f[++k] = q[i].r; } sort(f + 1, f + 1 + k); for(int i = 1; i <= k; i++) p[i] = i, w[i] = 0; int i = 0; for(i = 1; i <= m; i++){ int l = lower_bound(f+1, f+1+k, q[i].l) - f; int r = lower_bound(f+1, f+1+k, q[i].r) - f; int u = findP(l), v = findP(r); int d = 0; if(q[i].s[0] == 'o') d = 1; if(u == v && w[l]^d != w[r]) break; else if(u < v) p[u] = v, w[u] = w[l] ^ w[r] ^ d; else if(v < u) p[v] = u, w[v] = w[l] ^ w[r] ^ d; } cout << i - 1 << endl; return 0; }
思路:带权并查集。需要两个权重,分别对应两个点的x坐标相对位置和y坐标相对位置。代码一直有bug,以后再把代码贴上来吧。
思路:简单并查集。
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn = 2e3+10; int T, N, M; int p[maxn], w[maxn]; int findP(int x){ if(x != p[x]){ int px = p[x]; p[x] = findP(p[x]); w[x] ^= w[px]; } return p[x]; } void Union(int x,int y){ int px = findP(x), py = findP(y); if(px != py){ p[px] = py; w[px] = 1 ^ w[y] ^ w[x]; } } int main(){ cin >> T; for(int t = 1; t <= T; t++){ cin >> N >> M; for(int i = 1; i <= N; i++) p[i] = i, w[i] = 0; bool flag = false; while(M--){ int x, y; scanf("%d%d",&x,&y); int px = findP(x), py = findP(y); if(px != py){ Union(x,y); }else if(w[x] == w[y]){ flag = true; } } printf("Scenario #%d:\n",t); if(flag) puts("Suspicious bugs found!"); else puts("No suspicious bugs found!"); puts(""); } return 0; }
思路:枚举所有孩子情况,略。
ZOJ3261 Connections in Galaxy War
思路:注意输入只有0,和图不联通的情况。
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn = 1e5 + 5; int p[maxn]; bool vis[maxn]; int findP(int x){ return x == p[x] ? p[x] : p[x] = findP(p[x]); } int main(){ int a, b; while(cin >> a >> b && (a != -1 && b != -1)){ if(a == 0 && b == 0){ cout << "Yes" << endl; continue; } for(int i = 0; i < maxn; i++) p[i] = i, vis[i] = 0; bool flag = true; int cnt = 0; do { vis[a] = vis[b] = true; int pa = findP(a), pb = findP(b); if(pa != pb) p[pa] = pb, cnt++; else flag = false; cin >> a >> b; } while(a != 0 && b != 0); int tot = 0; for(int i = 1; i < maxn; i++) if(vis[i]) tot++; if(flag && cnt+1 == tot) cout << "Yes" << endl; else cout << "No" << endl; } return 0; }
思路:同上一题
#include <iostream> #include <algorithm> #include <stdio.h> using namespace std; const int maxn = 1e5 + 5; int p[maxn]; bool vis[maxn]; int findP(int x){ return x == p[x] ? p[x] : p[x] = findP(p[x]); } int main(){ int a, b, t = 0; while(cin >> a >> b && (a != -1 && b != -1)){ t++; if(a == 0 && b == 0){ printf("Case %d is a tree.\n", t); continue; } for(int i = 0; i < maxn; i++) p[i] = i, vis[i] = 0; bool flag = true; int cnt = 0; do { vis[a] = vis[b] = true; int pa = findP(a), pb = findP(b); if(pa != pb) p[pa] = pb, cnt++; else flag = false; cin >> a >> b; } while(a != 0 && b != 0); int tot = 0; for(int i = 1; i < maxn; i++) if(vis[i]) tot++; if(flag && cnt+1 == tot) printf("Case %d is a tree.\n", t); else printf("Case %d is not a tree.\n", t); } return 0; }

浙公网安备 33010602011771号