由于题目简单,部分题意写在代码中(简单题就应该多练英文…),且较少给注释,需要注意的地方会写在代码中,虽然四个题意各有千秋,但万变不离其宗,细细思考一番会发现四道题都属于很直接的最小生成树问题,由于博主时间原因,暂提供Kruskal解法。
这四题可以作为最小生成树(MST)入门的上手题库。
POJ1251(ZOJ1406)-Jungle Roads
1 //Kruskal-裸 2 //POJ1251-ZOJ1406 3 //找出维护道路的最小费用 4 //Time:0Ms Memory:168K 5 #include<iostream> 6 #include<cstring> 7 #include<cstdio> 8 #include<algorithm> 9 using namespace std; 10 11 #define MAXN 28 12 #define MAXM 80 13 14 struct Edge { 15 int u, v; 16 int d; 17 friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; } 18 }e[MAXM]; 19 20 int n, m; 21 int fa[MAXN]; 22 23 int Find(int x) 24 { 25 return fa[x] < 0 ? x : fa[x] = Find(fa[x]); 26 } 27 28 void Union(int r1,int r2) 29 { 30 int num = fa[r1] + fa[r2]; 31 if (r1 < r2) 32 { 33 fa[r2] = r1; 34 fa[r1] = num; 35 } 36 else { 37 fa[r1] = r2; 38 fa[r2] = num; 39 } 40 } 41 42 void kruskal() 43 { 44 int num = 0; 45 int minroad = 0; 46 memset(fa, -1, sizeof(fa)); 47 for (int i = 0; i < m; i++) 48 { 49 int r1 = Find(e[i].u); 50 int r2 = Find(e[i].v); 51 if (r1 == r2) continue; 52 minroad += e[i].d; 53 Union(r1, r2); 54 if (++num == n - 1) break; 55 } 56 printf("%d\n", minroad); 57 } 58 59 int main() 60 { 61 while (scanf("%d", &n), n) 62 { 63 m = 0; 64 for (int i = 1; i < n; i++) 65 { 66 int road; 67 char city[2]; 68 scanf("%s%d", city, &road); //用%c和getchar()会RE,可能是后台数据的问题 69 while (road--) 70 { 71 int d; 72 char c[2]; 73 scanf("%s%d", c, &d); 74 e[m].u = city[0] - 'A'; 75 e[m].v = c[0] - 'A'; 76 e[m++].d = d; 77 } 78 } 79 sort(e, e + m); 80 kruskal(); 81 } 82 return 0; 83 }
POJ1287(ZOJ1372)-Networking
1 //Kruskal-须查重边 2 //设计一个由给定所需网线长度的网络组成的最短网线方案(可能有重边) 3 //POJ1287-ZOJ1372 4 //Time:16Ms Memory:192K 5 #include<iostream> 6 #include<cstring> 7 #include<cstdio> 8 #include<algorithm> 9 using namespace std; 10 11 #define MAXN 51 12 13 struct Edge { 14 int u, v; 15 int d; 16 friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; } 17 }e[MAXN*MAXN]; 18 19 int n, m; 20 int fa[MAXN]; 21 int v[MAXN][MAXN]; //端点查边 22 int minroad; 23 24 int Find(int x) 25 { 26 return fa[x] < 0 ? x : fa[x] = Find(fa[x]); 27 } 28 29 void Union(int r1, int r2) 30 { 31 int num = fa[r1] + fa[r2]; 32 if (r1 < r2) 33 { 34 fa[r2] = r1; 35 fa[r1] = num; 36 } 37 else { 38 fa[r1] = r2; 39 fa[r2] = num; 40 } 41 } 42 43 void kruskal() 44 { 45 int num = 0; 46 minroad = 0; 47 memset(fa, -1, sizeof(fa)); 48 for (int i = 0; i < m; i++) 49 { 50 int r1 = Find(e[i].u); 51 int r2 = Find(e[i].v); 52 if (r1 == r2) continue; 53 Union(r1, r2); 54 minroad += e[i].d; 55 if (++num == n - 1) break; 56 } 57 printf("%d\n", minroad); 58 } 59 60 int main() 61 { 62 while (scanf("%d", &n), n) 63 { 64 memset(v, -1, sizeof(v)); 65 scanf("%d", &m); 66 for (int i = 0; i < m; i++) 67 { 68 scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d); 69 if (v[e[i].u][e[i].v] >= 0) //查重 70 { 71 e[v[e[i].u][e[i].v]].d = min(e[v[e[i].u][e[i].v]].d, e[i].d); 72 i--; m--; 73 } 74 else v[e[i].u][e[i].v] = i; 75 } 76 sort(e, e + m); 77 kruskal(); 78 } 79 return 0; 80 }
POJ2031(ZOJ1718)-Jungle Roads
1 //Kruskal+去重叠+简单几何 2 //题目不难,如果用到并查集,那么去重的部分需要考虑好 3 //Time:32Ms Memory:268K 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #include<cmath> 8 #include<algorithm> 9 using namespace std; 10 11 #define MAXN 105 12 #define POW2(x) ((x)*(x)) 13 #define DIS(i,j) (sqrt(POW2(v[i].x - v[j].x) + POW2(v[i].y - v[j].y) + POW2(v[i].z - v[j].z))) 14 15 struct Vertex { 16 double x, y, z; 17 double r; 18 }v[MAXN]; 19 20 struct Edge { 21 int u, v; 22 double d; 23 friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; } 24 }e[MAXN*MAXN]; 25 26 int n, m; 27 int fa[MAXN]; 28 29 int Find(int x) 30 { 31 return fa[x] < 0 ? x : fa[x] = Find(fa[x]); 32 } 33 34 void Union(int r1, int r2) 35 { 36 r1 = Find(r1); 37 r2 = Find(r2); 38 if (r1 == r2) return; //处理边的时候需要考虑,否则将RE 39 int num = fa[r1] + fa[r2]; 40 if (r1 < r2) 41 { 42 fa[r2] = r1; 43 fa[r1] = num; 44 } 45 else { 46 fa[r1] = r2; 47 fa[r2] = num; 48 } 49 } 50 51 void kruskal() 52 { 53 int num = 0; 54 double minroad = 0; 55 for (int i = 0; i < m; i++) 56 { 57 int r1 = Find(e[i].u); 58 int r2 = Find(e[i].v); 59 if (r1 == r2) continue; 60 Union(r1, r2); 61 minroad += e[i].d; 62 if (++num == n - 1) break; 63 } 64 printf("%.3lf\n", minroad); 65 } 66 67 int main() 68 { 69 while (scanf("%d", &n), n) 70 { 71 m = 0; 72 memset(fa, -1, sizeof(fa)); 73 for (int i = 0; i < n; i++) 74 { 75 scanf("%lf%lf%lf%lf", &v[i].x, &v[i].y, &v[i].z, &v[i].r); 76 for (int j = 0; j < i; j++) 77 { 78 double len = DIS(i, j) - v[i].r - v[j].r; 79 if (len <= 1e-5) 80 Union(i, j); //可能r1与r2同集合-在Union中处理 81 else { 82 e[m].u = i; 83 e[m].v = j; 84 e[m++].d = len; 85 } 86 } 87 } 88 sort(e, e + m); 89 kruskal(); 90 } 91 return 0; 92 }
POJ2421-Jungle Roads
1 //Kruskal-略变形 2 //Time:47Ms Memory:272K 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 #define MAX 105 9 10 struct Edge { 11 int u, v; 12 int d; 13 friend bool operator < (Edge e1, Edge e2) { return e1.d < e2.d; } 14 }e[MAX*MAX/2]; 15 16 int n, m; 17 int fa[MAX]; 18 int d[MAX][MAX]; 19 20 int Find(int x) 21 { 22 return fa[x] < 0 ? x : fa[x] = Find(fa[x]); 23 } 24 25 void Union(int r1, int r2) 26 { 27 r1 = Find(r1); 28 r2 = Find(r2); 29 if (r1 == r2) return; 30 int num = fa[r1] + fa[r2]; 31 if (fa[r1] < fa[r2]) 32 { 33 fa[r2] = r1; 34 fa[r1] = num; 35 } 36 else { 37 fa[r1] = r2; 38 fa[r2] = num; 39 } 40 } 41 42 void kruskal() 43 { 44 int minroad = 0; 45 int num = 0; 46 for (int i = 0; i < m; i++) 47 { 48 int r1 = Find(e[i].u); 49 int r2 = Find(e[i].v); 50 if (r1 == r2) continue; 51 Union(r1, r2); 52 minroad += e[i].d; 53 if (++num == n - 1) break; 54 } 55 printf("%d\n", minroad); 56 } 57 58 int main() 59 { 60 memset(fa, -1, sizeof(fa)); 61 scanf("%d", &n); 62 for (int i = 1; i <= n; i++) 63 for (int j = 1; j <= n; j++) 64 scanf("%d", &d[i][j]); 65 int k; 66 scanf("%d", &k); 67 while (k--) 68 { 69 int u, v; 70 scanf("%d%d", &u, &v); 71 Union(u, v); 72 } 73 m = 0; 74 for (int i = 1; i <= n; i++) 75 for (int j = 1; j < i; j++) 76 { 77 e[m].u = i; 78 e[m].v = j; 79 e[m++].d = d[i][j]; 80 } 81 sort(e, e + m); 82 kruskal(); 83 return 0; 84 }