HDU 1102 Constructing Roads

题目:

Problem Description

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected.

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
 

 

Input

The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j.

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
 

 

Output

You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.
 

 

Sample Input

3
0 990 692
990 0 179
692 179 0
1
1 2

Sample Output

179
 

题意:

  •  求连通各村庄所需修路长度的最短长度

 

思路:

  • 初始化成独立节点
  • 将连通的村庄间的所需修道路长度置为0代表无需修路,不再计入总的维修长度
  • 用结构体数组记录需要维修道路的两个村庄的编号及其间道路长度等信息,计算出结构体数组长度
  • 对结构体数组中存储的道路长度从小到大排序,便于求最短的维修长度

 

代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #define MAXN 101*50
 4 using namespace std;
 5 
 6 int pre[105];
 7 int m[105][105];   //存储每两个村庄之间的距离
 8 int n, q;
 9     
10 struct node{  //结构体存储两个村庄结点信息即其间的距离
11     int begin;
12     int end;
13     int len; 
14 }s[MAXN];
15 
16 bool cmp(node a, node b)
17 {
18     return a.len < b.len;
19 }
20 
21 void init(int n)
22 {
23     for(int i = 1; i <= n; i++)
24     {
25         pre[i] = i;
26     }
27     
28 }
29 
30 int find(int x)
31 {
32     while(x != pre[x])
33         x = pre[x];
34     
35     return x;
36 }
37 
38 int kruskal()
39 {
40     int k = 0;
41     for(int i = 1; i <= n; i++)  
42      {
43         for(int j = 1; j <= n; j++)
44         {
45             if(i > j)  //两村庄连通则可去可回,不重复记录
46             {
47                 s[k].begin = i;
48                 s[k].end = j;
49                 s[k].len = m[i][j];
50                 k++;  //记录需要连通的道路条数
51             }
52             
53         }
54     }
55     int minlen = 0;
56     sort(s, s + k, cmp);  //按需要修的道路的长度从小到大排序
57     for(int i = 0; i < k; i++)  //判断两节点的根节点是否相同
58     {
59         int fx = find(s[i].begin);
60         int fy = find(s[i].end);
61         if(fx != fy)
62         {
63             pre[fx] = fy;  //根节点不同则归并成同一结点并记入所需铺设的道路长度
64             minlen += s[i].len;
65         }
66     } 
67     return minlen;
68  } 
69 
70 int main()
71 {
72     while(scanf("%d", &n) != EOF)
73     {
74         init(n);
75         for(int i = 1; i <= n; i++)
76         {
77             for(int j = 1; j <= n; j++)
78               scanf("%d", &m[i][j]);
79         }
80         int x, y;    
81         scanf("%d", &q);
82         for(int i = 0; i < q; i++)    
83         {
84             scanf("%d %d", &x, &y);
85             m[x][y] = m[y][x] = 0;  //若两村庄已是连通的则无需修路,修路长度置为0
86         }
87 
88         printf("%d\n", kruskal());
89     }
90     return 0;
91 }

 总结:

对于最小生成树求最短路径问题,要同时记录结点和边,并将边按从小到大的顺序进行排序,而后再判断两个带边的节点的根节点是否相同,若相同则已连通,不再计入,否则计入。

 
posted @ 2019-07-06 13:38  Anzer  阅读(121)  评论(0编辑  收藏  举报