杭电1233--还是畅通工程(模板)

 

还是畅通工程

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 30823    Accepted Submission(s): 13828


Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
 

 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
 

 

Output
对每个测试用例,在1行里输出最小的公路总长度。
 

 

Sample Input
3 
1 2 1 
1 3 2 
2 3 4 
4 
1 2 1 
1 3 4 
1 4 1 
2 3 3 
2 4 2 
3 4 5 
0
 

 

Sample Output
 
3
5
Hint
Hint
Huge input, scanf is recommended.
 

 

Source
浙大计算机研究生复试上机考试-2006年
//并查集实现kruskal算法;
 1 #include <stdio.h>
 2 #include <algorithm>
 3 int father[110];
 4 using namespace std;
 5 
 6 struct vilage
 7 {
 8     int a,b,c;    
 9 };
10 vilage num[5000];
11 
12 bool cmp(vilage a, vilage b)
13 {
14     return a.c < b.c ;
15 }
16 
17 int find(int a)
18 {
19     while(father[a]!=a)
20     a = father[a];
21     return a;
22 }
23 
24 int mercy (int a, int b)
25 {
26     a=find(a) ;
27     b=find(b) ;
28     if(a != b)
29     {
30         father[a] = b ;
31         return 1;
32     }
33     return 0;
34 }
35 
36 int main()
37 {
38     int n;
39     while(~scanf("%d",&n),n)
40     { 
41         int i;
42         for(i=1; i<=n; i++)
43         father[i]=i ;
44         
45         n=n*(n-1)/2 ;
46         for(i=1;i<=n;i++)
47         scanf("%d %d %d",&num[i].a, &num[i].b, &num[i].c);    
48         sort(num+1,num+n+1,cmp);
49         
50         int total=0 ;
51         for(i=1; i<=n; i++)
52         {
53             if(mercy(num[i].a, num[i].b))
54             total+=num[i].c ;
55         }        
56         printf("%d
",total);
57     }
58     return 0;
59 }
 
 
//Prime() 算法; 
/*看上图,假设我们从节点1开始寻找(其实上面的程序就是这么干的,当然你可以假设从任意一个节点开始)。进入循环后,第一个for表示以某个节点
为基准(注意这个某个是以前已经找到的符合条件的),第二个for表示在基准点的基础上,寻找与基准点相连并且权值最小的(权值的意思就是上图线上的数字)。
简单模拟一下:从1开始,则通过第二个for可以发现1->2权值最小。所以把2节点加进set。然后分别以1和2为基准点,寻找与之相连的权值最小的点,找到后加入set,对了
,找到后别忘了把该节点标记为以符合,即对vis操作。就是这样循环,当道while中cur==n了,也就是说已经找玩n个点了,这时的值就是结果了。*/
View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 int map[1010][1010];
 4 int vis[1010];  //标记点是否已经被选 ; 
 5 int s[1010];    //符合要求的点的集合; 
 6 int n;
 7 int prim()
 8 {
 9     int cur=0, y, min, sum = 0;
10     s[++cur] = 1;
11     vis[cur] = 1;
12     while(cur < n)
13     {
14         min = 1000000;
15         for(int i = 1; i<=cur; i++)
16         {
17             for(int j = 1; j<=n; j++)
18             {
19                 if(!vis[j] && map[s[i]][j] < min)
20                 {
21                     min = map[s[i]][j];
22                     y = j;
23                 }
24             }
25         }
26         sum += min;
27         vis[y] = 1;
28         s[++cur] = y;
29     }
30     return sum;
31 }
32 int main()
33 {
34     int m;
35     while(~scanf("%d", &n), n)
36     {
37         memset(vis, 0, sizeof(vis));
38         memset(s, 0, sizeof(s));
39         m = n * (n-1) / 2;
40         for(int i=0; i<m; i++)
41         {
42             int a, b, c;
43             scanf("%d %d %d", &a, &b, &c);
44             map[a][b] = map[b][a] = c;
45         }
46         int sum = prim();
47         printf("%d
", sum);
48     }
49     return 0;
50 }
 
原文地址:https://www.cnblogs.com/soTired/p/4612357.html