板子:
1 int V, E; 2 int p[MAXN]; 3 int r[MAXN]; 4 5 void init(int n) { 6 for (int i = 1; i <= n; i++) { 7 p[i] = i, r[i] = 0; 8 } 9 } 10 11 int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } 12 13 bool same(int x, int y) { return find(x) == find(y); } 14 15 void unite(int x, int y) { 16 x = find(x); 17 y = find(y); 18 if (x == y) return; 19 if (r[x] < r[y]) { 20 p[x] = y; 21 } else { 22 p[y] = x; 23 if (r[x] == r[y]) r[x]++; 24 } 25 } 26 27 struct Edge { 28 int u, v, cost; 29 } edge[MAXM]; 30 bool cmp(const Edge& e1, const Edge& e2) { return e1.cost < e2.cost; } 31 int Kruskal() { 32 sort(edge + 1, edge + R + 1, cmp); 33 init(V); 34 int res = 0; 35 for (int i = 1; i <= E; i++) { 36 Edge e = edge[i]; 37 if (!same(e.u, e.v)) { 38 unite(e.u, e.v); 39 res += e.cost; 40 } 41 } 42 return res; 43 }
题意:N个城堡,M个桥,每个桥的权值都不一样,题目要求能使城堡彼此联通的所有桥集合里面权值最小的那种,由此可以判断这是一道求最小生成树的题。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 6 const int maxn = 2000 + 5, maxm = 2e5 + 5; 7 struct edge { 8 int u, v, value; 9 }myedge[maxm]; 10 int p[maxn], n, m; 11 12 bool cmp(const edge&p1,const edge&p2) { 13 return p1.value < p2.value; 14 } 15 16 int find(int x) { 17 return (p[x] == x) ? x : (p[x] = find(p[x])); 18 } 19 20 int main() { 21 scanf("%d%d", &n, &m); 22 int a, b, id, k = 0; 23 ll w; 24 for (int i = 0; i < m; i++) { 25 scanf("%d%d%lld%d", &a, &b, &w, &id); 26 if (id == 1) { 27 myedge[k].u = a; 28 myedge[k].v = b; 29 myedge[k].value = w; 30 k++; 31 } 32 } 33 if (k != 0) { 34 for (int i = 0; i < n; i++) { 35 p[i] = i; 36 } 37 sort(myedge, myedge + k, cmp); 38 int x, y, counter = 0; 39 ll value, sum = 0; 40 for (int i = 0; i < k; i++) { 41 value = myedge[i].value; 42 x = find(myedge[i].u); 43 y = find(myedge[i].v); 44 if (x != y) { 45 sum += value; 46 p[y] = x; 47 counter++; 48 if (counter >= n - 1) break; 49 } 50 } 51 printf("yes %lld ", sum); 52 } 53 else printf("no"); 54 return 0; 55 }
POJ3723
题意:有 N 个男人 M 个女人,给出若干男女之间的 1~9999 之间的亲密度关系,征募某个人的费用是 10000 -(已经征募到的人中和自己的亲密度的最大值)。要求通过适当的征募顺序使得所有人的所需费用最小
解法:把人与人看做点,则这个问题就转换为无向图中的最大权森林问题。将最小生成树中的边权去反即可用最小生成树的算法求解。
1 int N, M, R; 2 int p[MAXN]; 3 int r[MAXN]; 4 5 void init(int n) { 6 for (int i = 1; i <= n; i++) { 7 p[i] = i, r[i] = 0; 8 } 9 } 10 11 int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); } 12 13 bool same(int x, int y) { return find(x) == find(y); } 14 15 void unite(int x, int y) { 16 x = find(x); 17 y = find(y); 18 if (x == y) return; 19 if (r[x] < r[y]) { 20 p[x] = y; 21 } else { 22 p[y] = x; 23 if (r[x] == r[y]) r[x]++; 24 } 25 } 26 27 struct Edge { 28 int u, v, cost; 29 } edge[MAXM]; 30 31 bool cmp(const Edge& e1, const Edge& e2) { return e1.cost < e2.cost; } 32 33 LL Kruskal() { 34 sort(edge + 1, edge + R + 1, cmp); 35 init(N + M); 36 LL res = 0; 37 for (int i = 1; i <= R; i++) { 38 Edge e = edge[i]; 39 if (!same(e.u, e.v)) { 40 unite(e.u, e.v); 41 res += e.cost; 42 } 43 } 44 return res; 45 } 46 47 int main() { 48 // freopen("input.txt", "r", stdin); 49 int T; 50 scanf("%d", &T); 51 while (T--) { 52 scanf("%d%d%d", &N, &M, &R); 53 REP(i, 1, R) { 54 scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost); 55 edge[i].u++, edge[i].v++; 56 edge[i].cost = 0 - edge[i].cost; 57 edge[i].v = edge[i].v + N; 58 } 59 printf("%lld ", 10000 * 1ll * (N + M) + Kruskal()); 60 } 61 return 0; 62 }