<hdu - 1863> 畅通工程 并查集和最小生成树问题
本题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863
Problem Description:
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input:
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output:
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input:
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
Sample Output:
3
?
解题思路:村庄(支点)之间修公路,给出之间需要的的修路费(权值),如果输入的统计数据不足的话,最后输出的时候输出“?”。这道题既可以用并查集解也可以用最小生成树求解,差不多都可以算是套模板的题,只是最后输出“?”的时候需要点技巧:
最小生成树代码:
1 #include <iostream> 2 #include <algorithm> 3 #define maxn 105 4 #define INF 999999 5 6 using namespace std; 7 int M, N;///M是村庄数、N是道路数 8 bool used[maxn]; 9 int cost[maxn][maxn]; 10 int mincost[maxn]; 11 12 int prim () { 13 for (int i = 1; i <= M; ++i) { 14 mincost[i] = INF; 15 used[i] = false; 16 } 17 mincost[1] = 0; 18 int res = 0; 19 while (true) { 20 int v = -1; 21 for (int u = 1; u <= M; ++u) { 22 if (!used[u] && (v == -1 || mincost[u] < mincost[v])) v = u; 23 } 24 if (v == -1) break; 25 if (mincost[v] == INF) return INF;///使用这种方法检查输出"?"的情况. 26 used[v] = true; 27 res += mincost[v]; 28 for (int u = 1; u <= M; ++u) { 29 mincost[u] = min (mincost[u], cost[v][u]); 30 } 31 } 32 return res; 33 } 34 35 int main () { 36 int a, b, w; 37 while ((cin >> N) && N ) { 38 // int flag = 0; 39 cin >> M; 40 for (int i = 1;i <= M; ++i) 41 for (int j = 1;j <= M; ++j) 42 cost[i][j] = INF; 43 for (int i = 1; i <= N; ++i) { 44 cin >> a >> b >> w; 45 cost[b][a] = cost[a][b] = w; 46 } 47 /* for (int i = 1; i <= M; ++i){ 48 for (int j = 1; j <= M; ++j) { 49 if (cost[i][j] == INF && i != j) 50 flag = 1; 51 }//一开始是用这种方法检查单独的点的,(错误) 52 }*/ 53 int res = prim (); 54 if (res == INF) 55 cout << "?" << endl; 56 else 57 cout << res << endl; 58 } 59 return 0; 60 }
最小生成树(输出“?”技巧):在计算的时候做一个选择的点是否是正无穷的判断(如果一个点是孤立的话,当取到最后的时候会将代码中的v赋值到那个被孤立的点,那个点没有赋值权值,所以就是正无穷)。
并查集代码:
1 #include<cstdio> 2 #include<cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 int pre[200]; 8 struct road { //公路的结构体 9 int x, y, v; 10 }ad[6000]; 11 12 bool cmp(road a, road b) { 13 return a.v < b.v; 14 } 15 16 int find(int x) { //寻找 17 if(pre[x] != x) 18 return pre[x] = find(pre[x]); 19 return pre[x]; 20 } 21 22 int mix(int x,int y) { //合并 23 int fx = find(x), fy = find(y); 24 if(fx == fy) 25 return 0; 26 pre[fy] = fx; 27 return 1; 28 } 29 30 int main() { 31 int i, j, n, m; 32 int ans; 33 int count; 34 while(~scanf("%d%d",&m,&n)) { 35 if (m == 0) 36 break; 37 for(j = 0; j < m; j++) 38 scanf("%d%d%d",&ad[j].x ,&ad[j].y,&ad[j].v); 39 for(i = 0; i <= n; i++) 40 pre[i] = i; 41 ans = 0; 42 count = 0; 43 sort(ad, ad+m, cmp); 44 for(i = 0; i < m; ++i) { 45 if(count == n - 1) break; 46 if(mix(ad[i].x, ad[i].y)) { 47 ++ count; /////在这里判断输出"?"的时候 48 ans = ans + ad[i].v; 49 } 50 } 51 if(count != n - 1) 52 printf("?\n"); 53 else 54 printf("%d\n",ans); 55 } 56 return 0; 57 }
并查集(输出“?”技巧):另外定义一个变量,在计算的时候自加,最后判断和“M - 1”(M是村庄的数目)的关系,因为离散的点连成一条线之间的道路条数就是M-1。
欢迎码友评论,一起成长。