首页 > 代码库 > hdu1162(最小生成树 prim or kruscal)

hdu1162(最小生成树 prim or kruscal)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1162

意义:给出一些点,用线问使所有点直接或间接连通,需要多长;

思路:裸最小生成树;

法1:

prim算法:MST(Minimum Spanning Tree,最小生成树)问题有两种通用的解法,Prim算法就是其中之一,它是从点的方面考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。(这短话复制的别人的,感觉写的蛮好的)

prim算法就是从待选点集中依次选出距离已选点集中距离最小的点加入已选点集中;

 

代码:

 1 #include <iostream>
 2 #include <math.h>
 3 #include <algorithm>
 4 #include <string.h>
 5 #include <stdio.h>
 6 #define MAXN 100+10
 7 #define INF 9999999999
 8 using namespace std;
 9 
10 int n, tag[MAXN];
11 double mp[MAXN][MAXN], low[MAXN];
12 
13 double prime(void){
14     memset(tag, 0, sizeof(tag));  //×××标记数组清 0
15     int s=1;
16     double cnt=0;
17     for(int i=1; i<=n; i++){   //×××从点 1 开始
18         low[i]=mp[s][i];
19     }
20     for(int i=2; i<=n; i++){
21         double min=INF;
22         for(int j=2; j<=n; j++){  //×××找到未添加点中到以添加点中距离最近的点即当前要添加的点
23             if(!tag[j]&&min>low[j]){
24                 min=low[j];
25                 s=j;
26             }
27         }
28         cnt+=min;      //***本题中不存在不能连同的情况,所以不需要加 if(min>=INF) return -1
29         tag[s]=1;
30         for(int j=2; j<=n; j++){
31             if(!tag[j]&&low[j]>mp[s][j]){  //×××更新low数组
32                 low[j]=mp[s][j];
33             }
34         }
35     }
36     return cnt;
37 }
38 
39 int main(void){
40     while(~scanf("%d", &n)){
41         pair<double, double> p[MAXN];
42         for(int i=1; i<=n; i++){
43             scanf("%lf%lf", &p[i].first, &p[i].second);
44         }
45         for(int i=1; i<=n; i++){
46             for(int j=1; j<=n; j++){
47                 mp[i][j]=sqrt((p[j].first-p[i].first)*(p[j].first-p[i].first)+(p[j].second-p[i].second)*(p[j].second-p[i].second));
48             }
49         }
50         double ans=prime();
51         printf("%.2lf\n", ans);
52     }
53     return 0;
54 }

 

法2:

kruscal算法:

将图中边按其权值由小到大的次序顺序选取,若选边后不形成回路,则保留作为一条边,若形成回路则除去.依次选够(n-1)条边,即得最小生成树.(n为顶点数)

 

代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <stdio.h>
 4 #include <math.h>
 5 #define MAXN 10000+10
 6 using namespace std;
 7 
 8 struct node{
 9     int x, y;
10     double weight;
11 }map[MAXN];
12 
13 int m, n, pre[MAXN];
14 
15 bool cmp(node a, node b){
16     return a.weight < b.weight;
17 }
18 
19 int find(int x){
20     while(pre[x]!=x){
21         x=pre[x];
22     }
23     return x;
24 }
25 
26 double join(node a){
27     int px=find(a.x);
28     int py=find(a.y);
29     if(px!=py){
30         pre[px]=py;
31         return a.weight;
32     }else{
33         return 0;   //××××若成环则返回 0
34     }
35 }
36 
37 double kruskal(void){
38     for(int i=1; i<=n; i++){
39         pre[i]=i;
40     }
41     double cnt=0;
42     sort(map, map+m, cmp);
43     for(int i=0; i<m; i++){
44         cnt+=join(map[i]);
45     }
46     return cnt;
47 }
48 
49 int main(void){
50     while(~scanf("%d", &n)){
51         pair<double, double> p[MAXN];
52         for(int i=1; i<=n; i++){
53             scanf("%lf%lf", &p[i].first, &p[i].second);
54         }
55         int k=0;
56         for(int i=1; i<=n; i++){
57             for(int j=i+1; j<=n; j++){
58                 double cnt=sqrt((p[i].first-p[j].first)*(p[i].first-p[j].first)+(p[i].second-p[j].second)*(p[i].second-p[j].second));
59                 map[k].x=i;
60                 map[k].y=j;
61                 map[k].weight=cnt;
62                 k++;
63             }
64         }
65         m=k;
66         double ans=kruskal();
67         printf("%.2lf\n", ans);
68     }
69     return 0;
70 }

 

hdu1162(最小生成树 prim or kruscal)