最小生成树MST

不懂什么是最小生成树的可以看-->这个博客

 

Prim  适合点少

此算法可以称为”加点法“,每次迭代选择代价最小的边对应的点,加入到最小生成树中。

 

Kruskal  适合边少

此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

(感觉就是并查集)

 

例题    hdu1233还是畅通工程

 

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

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

Prim

156ms  1424k

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 #define mem(a) memset(a,0,sizeof(a))
 6 #define ll long long
 7 
 8 const int inf = 0x3f3f3f3f;
 9 const int maxn = 110;
10 
11 int map[maxn][maxn];
12 bool vis[maxn];
13 int dis[maxn];
14 int n;
15 void init()
16 {
17     for(int i = 1; i <= 100; i++)
18         for(int j = 1; j <= 100; j++)
19             if(i==j)    map[i][j] = 0;
20             else        map[i][j] = inf;
21 }
22 
23 int prim()
24 {
25     int ans = 0;
26     for(int i = 1; i <= n; i++)
27         dis[i] = map[1][i];
28     mem(vis);
29     vis[1] = 1;
30     int k;
31     for(int i = 2; i <= n; i++)
32     {
33         int min = inf;
34         for(int j = 1; j <= n; j++)
35             if(!vis[j] && min > dis[j])
36             {
37                 min = dis[j];
38                 k = j;
39             }
40         vis[k] = 1;
41         ans += min;
42         for(int j = 1; j <= n; j++)
43         {
44             if(!vis[j] && dis[j] > map[k][j])
45                 dis[j] = map[k][j];
46         }
47     }
48     return ans;
49 }
50 
51 int main()
52 {
53     while(scanf("%d",&n)&&n)
54     {
55         int m = n*(n-1)/2;
56         init();
57         int u,v,val;
58         for(int i = 1; i <= m; i++)
59         {
60             scanf("%d%d%d",&u,&v,&val);
61             map[u][v] = map[v][u] = val;
62         }
63         int ans = prim();
64         printf("%d\n",ans);
65     }
66     return 0;
67 }
Prim

Kruskal

187ms  1456k

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define mem(a) memset(a,0,sizeof(a))
 7 #define ll long long
 8 const int maxn = 100100;
 9 struct node
10 {
11     int u,v,val;
12 }a[maxn];
13 
14 int pre[110];
15 
16 bool cmp(node a,node b)
17 {
18     return a.val < b.val;
19 }
20 
21 int find(int x)
22 {
23     if(x == pre[x])
24         return x;
25     return pre[x] = find(pre[x]);
26 }
27 
28 void unite(int x,int y)
29 {
30     x = find(x);
31     y = find(y);
32     pre[y] = x;
33 }
34 
35 int main()
36 {
37     int n;
38     while(scanf("%d",&n)&&n)
39     {
40         int m = n*(n-1)/2;
41         for(int i = 1; i <= n; i++) pre[i] = i;
42         for(int i = 0; i < m; i++)
43             scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].val);
44         sort(a,a+m,cmp);
45         int ans = 0;
46         for(int i = 0; i < m; i++)
47         {
48             if(find(a[i].u)!=find(a[i].v))
49             {
50                 unite(a[i].u,a[i].v);
51                 ans += a[i].val;
52             }
53         }
54         printf("%d\n",ans);
55     }
56     return 0;
57 }
Kruskal

 

 

例题    hdu1875畅通工程再续

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

Input

输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。

每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

Prim

15ms  1432k

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define mem(a) memset(a,0,sizeof(a))
 5 #define ll long long
 6 
 7 const int maxn = 110;
 8 const double inf = 100000.1;
 9 double dis[maxn];//距离
10 bool vis[maxn];//标记数组
11 double ans;//答案
12 int n;//n个岛
13 
14 struct node
15 {
16     int x,y;
17 } a[maxn];
18 
19 double dist(int i,int j)
20 {
21     int dx = a[i].x-a[j].x;
22     int dy = a[i].y-a[j].y;
23     return sqrt((double)(dx*dx+dy*dy));
24 }
25 
26 void prim()
27 {
28     int k = 0;
29     for(int i = 1; i < n; i++)
30     {
31         if(dist(k,i) >= 10.0 && dist(k,i) <= 1000.0)
32             dis[i] = dist(0,i);
33         else
34             dis[i] = inf;
35     }
36     mem(vis);
37     vis[k] = 1;
38     ans = 0;
39     for(int i = 1; i < n; i++)
40     {
41         double min = inf;
42         for(int j = 0; j < n; j++)
43         {
44             if(!vis[j] && min>dis[j])
45             {
46                 if(dis[j] >= 10.0 && dis[j] <= 1000.0)
47                 {
48                     min = dis[j];
49                     k = j;
50                 }
51             }
52         }
53         if(min < inf)
54         {
55             ans += min;
56             vis[k] = 1;
57         }
58         for(int j = 0; j < n; j++)
59         {
60             if(!vis[j] && dis[j] > dist(k,j))
61             {
62                 if(dist(k,j) >= 10.0 && dist(k,j) <= 1000.0)
63                     dis[j] = dist(k,j);
64             }
65         }
66     }
67 }
68 
69 int main()
70 {
71     ios::sync_with_stdio(false);
72     cin.tie(0),cout.tie(0);
73     int t;
74     cin>>t;
75     while(t--)
76     {
77         cin>>n;
78         for(int i = 0; i < n; i++)
79             cin>>a[i].x>>a[i].y;
80 
81         prim();
82 
83         bool flag = true;
84         for(int i = 0; i < n; i++)
85         {
86             if(!vis[i])
87             {
88                 flag = false;
89             }
90         }
91         if(flag)
92             printf("%.1f\n",ans*100);
93         else
94             printf("oh!\n");
95     }
96 }
Prim

Kruskal

78ms  1524k

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 using namespace std;
  7 
  8 #define mem(a) memset(a,0,sizeof(a))
  9 #define ll long long
 10 const int maxn = 110;
 11 int pre[maxn];
 12 
 13 struct node
 14 {
 15     int x,y;
 16 } a[maxn];
 17 
 18 struct m
 19 {
 20     int u,v;
 21     double val;
 22 } b[5100];
 23 
 24 int find(int x)
 25 {
 26     if(x == pre[x])
 27         return x;
 28     return pre[x] = find(pre[x]);
 29 }
 30 
 31 void unite(int x,int y)
 32 {
 33     x = find(x);
 34     y = find(y);
 35     pre[y] = x;
 36 }
 37 
 38 double dis(int i,int j)
 39 {
 40     int dx = a[i].x - a[j].x;
 41     int dy = a[i].y - a[j].y;
 42     return sqrt((double)(dx*dx+dy*dy));
 43 }
 44 
 45 bool cmp(m x,m y)
 46 {
 47     return x.val < y.val;
 48 }
 49 
 50 int main()
 51 {
 52     ios::sync_with_stdio(false);
 53     cin.tie(0),cout.tie(0);
 54     int t,n;
 55     cin>>t;
 56     while(t--)
 57     {
 58         cin>>n;
 59         for(int i = 0; i < n; i++)
 60         {
 61             cin>>a[i].x>>a[i].y;
 62             pre[i] = i;
 63         }
 64         int k = 0;
 65         for(int i = 0; i < n; i++)
 66         {
 67             for(int j = i+1; j < n; j++)
 68             {
 69                 b[k].u = i;
 70                 b[k].v = j;
 71                 b[k].val = dis(i,j);
 72                 k++;
 73             }
 74         }
 75         sort(b,b+k,cmp);
 76         double ans = 0;
 77         for(int i = 0; i < k; i++)
 78         {
 79             if(find(b[i].u) != find(b[i].v))
 80             {
 81                 if(b[i].val >= 10.0 && b[i].val <= 1000.0)
 82                 {
 83                     ans += b[i].val;
 84                     unite(b[i].u,b[i].v);
 85                 }
 86             }
 87         }
 88         bool flag = true;
 89         int temp = find(0);
 90         for(int i = 1; i < n; i++)
 91         {
 92             if(find(i) != temp)
 93             {
 94                 flag = false;
 95                 break;
 96             }
 97         }
 98         if(flag)
 99             printf("%.1f\n",ans*100);
100         else
101             printf("oh!\n");
102     }
103     return 0;
104 }
kruskal

 

 

 

posted on 2019-08-13 15:05  By_布衣  阅读(172)  评论(0编辑  收藏  举报

导航