最小生成树练习1(克鲁斯卡尔算法Kruskal)

今天刷一下水题练手入门,明天继续。

poj1861 Network(最小生成树)新手入门题。

题意:输出连接方案中最长的单根网线长度(必须使这个值是所有方案中最小的),然后输出方案。

题解:本题没有直接求生成树,但如果连接n个集线器的方案多于n-1条边,那么必存在回路,因此去掉某些边剩下的边和所有顶点构成一个生成树。对于一个图的最小生成树来说,它的最大边满足所有生成树的最大边里最小,正和题意。

吐槽:题目样例是错的。。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1001;
 6 struct edge{
 7     int u,v,w;
 8 }e[15001];
 9 int f[N],a[N],ai;
10 int n,m,ma;
11 int cmp(edge a,edge b){
12     return a.w<b.w;
13 }
14 void init(){
15     for(int i=1;i<=n;++i)
16         f[i]=i;
17 }
18 int fin(int x){
19     if(x!=f[x])f[x]=fin(f[x]);
20     return f[x];
21 }
22 void Kruskal(){
23     ma=ai=0;
24     int u,v,i;
25     init();
26     for(i=0;i<m;++i){
27         u=e[i].u;
28         v=e[i].v;
29         if((u=fin(u))!=(v=fin(v))){
30             f[u]=v;
31             a[ai++]=i;
32             ma=max(e[i].w,ma);
33         }
34         if(ai>=n-1)break;
35     }
36 }
37 int main(){
38     int i,u,v,w;
39     scanf("%d%d",&n,&m);
40     for(i=0;i<m;++i){
41         scanf("%d%d%d",&u,&v,&w);
42         e[i]=edge{u,v,w};
43     }
44     sort(e,e+m,cmp);
45     Kruskal();
46     printf("%d\n%d\n",ma,ai);
47     for(i=0;i<ai;++i)
48         printf("%d %d\n",e[a[i]].u,e[a[i]].v);
49     return 0;
50 }

poj1251 Jungle Roads(最小生成树)水题。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=27;
 6 struct edge{
 7     int u,v,w;
 8 }e[75];
 9 int f[N];
10 int n,m,ans;
11 int cmp(edge a,edge b){
12     return a.w<b.w;
13 }
14 void init(){
15     for(int i=0;i<n;++i)
16         f[i]=i;
17 }
18 int fin(int x){
19     if(x!=f[x])f[x]=fin(f[x]);
20     return f[x];
21 }
22 void Kruskal(){
23     ans=0;
24     int u,v,i;
25     init();
26     for(i=0;i<m;++i){
27         u=e[i].u;
28         v=e[i].v;
29         if((u=fin(u))!=(v=fin(v))){
30             f[u]=v;
31             ans+=e[i].w;
32         }
33     }
34 }
35 int main(){
36     int i,j,w,k;
37     char u[3],v[3];
38     while(scanf("%d",&n),n){
39         m=0;
40         for(i=0;i<n-1;++i){
41             scanf("%s %d",u,&k);
42             for(j=0;j<k;++j){
43                 scanf("%s %d",v,&w);
44                 e[m++]={u[0]-‘A‘,v[0]-‘A‘,w};
45             }
46         }
47         sort(e,e+m,cmp);
48         Kruskal();
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

poj1287 Networking(最小生成树)水题。

用prim要注意两个地点之间的线路可能多条,即有重边。我这里练的是Kruskal,题目没给边数,但知道点数最多50,则边数最多50*49/2=1225条,有重边,开大点数组就行,因为数据弱,随便开个1500都过了,醉。。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int M=1500;
 6 struct edge{
 7     int u,v,w;
 8 }e[M];
 9 int f[50];
10 int n,m,ans;
11 int cmp(edge a,edge b){
12     return a.w<b.w;
13 }
14 void init(){
15     for(int i=1;i<=n;++i)
16         f[i]=i;
17 }
18 int fin(int x){
19     if(x!=f[x])f[x]=fin(f[x]);
20     return f[x];
21 }
22 void Kruskal(){
23     ans=0;
24     int u,v,i;
25     init();
26     for(i=0;i<m;++i){
27         u=e[i].u;
28         v=e[i].v;
29         if((u=fin(u))!=(v=fin(v))){
30             f[u]=v;
31             ans+=e[i].w;
32         }
33     }
34 }
35 int main(){
36     int i,u,v,w;
37     while(scanf("%d",&n),n){
38         scanf("%d",&m);
39         for(i=0;i<m;++i){
40             scanf("%d%d%d",&u,&v,&w);
41             e[i]={u,v,w};
42         }
43         sort(e,e+m,cmp);
44         Kruskal();
45         printf("%d\n",ans);
46     }
47     return 0;
48 }

poj2031 Building a Space Station(最小生成树)题目看老久,其实挺水…空间站存在一些球形单间,如果单间之间接触,重叠或用走廊连接则连通。给出单间坐标和半径,求要使得所有单间相连通的走廊总长度的最小值。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const int M=5000;
 7 const int N=100;
 8 struct edge{
 9     int u,v;
10     double w;
11 }e[M];
12 double a[N],b[N],c[N],r[N];
13 int f[N];
14 int n,m;
15 double ans;
16 int cmp(edge a,edge b){
17     return a.w<b.w;
18 }
19 double dist(int i,int j){
20     return sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])+(c[i]-c[j])*(c[i]-c[j]))-r[i]-r[j];
21 }
22 void init(){
23     for(int i=0;i<n;++i) f[i]=i;
24 }
25 int fin(int x){
26     if(x!=f[x])f[x]=fin(f[x]);
27     return f[x];
28 }
29 void Kruskal(){
30     ans=0;
31     int u,v,i,cnt=0;
32     init();
33     for(i=0;cnt<n-1;++i){
34         u=e[i].u;
35         v=e[i].v;
36         if((u=fin(u))!=(v=fin(v))){
37             f[u]=v;
38             ans+=e[i].w;
39             cnt++;
40         }
41     }
42 }
43 int main(){
44     int i,j;
45     double w;
46     while(scanf("%d",&n),n){
47         for(i=0;i<n;++i){
48             scanf("%lf%lf%lf%lf",&a[i],&b[i],&c[i],&r[i]);
49         }
50         for(m=i=0;i<n-1;++i){
51             for(j=i+1;j<n;++j){
52                 w=dist(i,j);
53                 if(w<0) w=0;
54                 e[m++]={i,j,w};
55             }
56         }
57         sort(e,e+m,cmp);
58         Kruskal();
59         printf("%.3f\n",ans);
60     }
61     return 0;
62 }

poj2421 Constructing Roads(最小生成树)水题。有些点已经连边,进行标记,加边时将其边赋值为0即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int M=5000;
 6 const int N=101;
 7 struct edge{
 8     int u,v,w;
 9 }e[M];
10 int f[N];
11 int g[N][N],vis[N][N];
12 int n,ans;
13 int cmp(edge a,edge b){
14     return a.w<b.w;
15 }
16 void init(){
17     for(int i=1;i<=n;++i) f[i]=i;
18 }
19 int fin(int x){
20     if(x!=f[x])f[x]=fin(f[x]);
21     return f[x];
22 }
23 void Kruskal(){
24     ans=0;
25     int u,v,i,cnt=0;
26     init();
27     for(i=0;cnt<n-1;++i){
28         u=e[i].u;
29         v=e[i].v;
30         if((u=fin(u))!=(v=fin(v))){
31             f[u]=v;
32             ans+=e[i].w;
33             cnt++;
34         }
35     }
36 }
37 int main(){
38     int i,j,a,b,ei,m;
39     while(scanf("%d",&n)==1){
40         for(i=1;i<=n;++i)
41             for(j=1;j<=n;++j)
42             scanf("%d",&g[i][j]);
43         memset(vis,0,sizeof(vis));
44         scanf("%d",&m);
45         while(m--){
46             scanf("%d%d",&a,&b);
47             vis[a][b]=1;
48         }
49         ei=0;
50         for(i=1;i<n;++i){
51             for(j=i+1;j<=n;++j){
52                 if(vis[i][j]) e[ei++]={i,j,0};
53                 else  e[ei++]={i,j,g[i][j]};
54             }
55         }
56         sort(e,e+ei,cmp);
57         Kruskal();
58         printf("%d\n",ans);
59     }
60     return 0;
61 }

时间: 2024-10-13 21:23:19

最小生成树练习1(克鲁斯卡尔算法Kruskal)的相关文章

贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal&amp;#39;s algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个.这里面充分体现了贪心算法的精髓.大致的流程能够用一个图来表示.这里的图的选择借用了Wikipedia上的那个.很清晰且直观. 首先第一步,我们有一张图,有若干点和边 例如以下图所看到的: 第一步我们要做的事情就是将全部的边的长度排序,用排序的结果作为我们选择边的根据.这里再次体现了贪心算法的思想.资源排序,对局部最优的资源进行选择. 排序完毕后,我们领先选择了边AD. 这样我们的图就变成了 第

hdu-1863畅通工程 最小生成树克鲁斯卡尔算法kruskal(并查集实现)

畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 16994    Accepted Submission(s): 7134 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出

最小生成树之克鲁斯卡尔(Kruskal)算法

学习最小生成树算法之前我们先来了解下 下面这些概念: 树(Tree):如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树. 生成树是连通图的极小连通子图.这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路:若去掉一条边,将会使之变成非连通图. 最小生成树(Minimum Spanning Tree,MST):或者称为最小代价树Minimum-cost Spanning Tr

最小生成树(MST)----普里姆(Prim)算法与克鲁斯卡尔(Kruskal)算法

1.概念:给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树. 2.应用:例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低.这就需要找到带权的最小生成树. 3.求最小生成树的算法 3.1 普里姆(Prim)算法 方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树

c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树

c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树 最小生成树(Minimum Cost Spanning Tree)的概念: 假设要在n个城市之间建立公路,则连通n个城市只需要n-1条线路.这时,自然会考虑,如何在最节省经费的前提下建立这个公路网络. 每2个城市之间都可以设置一条公路,相应地都要付出一定的经济代价.n个城市之间,最多可以设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少? 克鲁斯卡尔(kruskal)算法的大致思路: 把每条边的权重

JS实现最小生成树之克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔算法打印最小生成树: 构造出所有边的集合 edges,从小到大,依次选出筛选边打印,遇到闭环(形成回路)时跳过. JS代码: 1 //定义邻接矩阵 2 let Arr2 = [ 3 [0, 10, 65535, 65535, 65535, 11, 65535, 65535, 65535], 4 [10, 0, 18, 65535, 65535, 65535, 16, 65535, 12], 5 [65535, 18, 0, 22, 65535, 65535, 65535, 65535,

最小生成树--克鲁斯卡尔算法(Kruskal)

按照惯例,接下来是本篇目录: $1 什么是最小生成树? $2 什么是克鲁斯卡尔算法? $3 克鲁斯卡尔算法的例题 摘要:本片讲的是最小生成树中的玄学算法--克鲁斯卡尔算法,然后就没有然后了. $1 什么是最小生成树? •定义: 先引入一个定理:N个点用N-1条边连接成一个联通块,形成的图形只可能是树,没有别的可能: 根据这个定理,我们定义:在一个有N个点的图中,选出N-1条边出来,连接所有N个点,这N-1条边的边权之和最小的方案: •最小生成树之prim算法:   由于本蒟蒻还不会这个算法,所以

最小生成树(普利姆算法、克鲁斯卡尔算法)

给定一个加权无向连通图,如何选择一个生成树,使权利的最小总和的边缘所有树,叫最小生成树. 求最小生成树算法 (1) 克鲁斯卡尔算法 图的存贮结构採用边集数组,且权值相等的边在数组中排列次序能够是随意的.该方法对于边相对照较多的不是非常有用,浪费时间. (2) p=1313">普里姆算法 图的存贮结构採用邻接矩阵.此方法是按各个顶点连通的步骤进行,须要用一个顶点集合,開始为空集,以后将以连通的顶点陆续增加到集合中,所有顶点增加集合后就得到所需的最小生成树 . 以下来详细讲下: 克鲁斯卡尔算法

(转)最小生成树之普利姆算法、克鲁斯卡尔算法

 最小生成树之prim算法 边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以把边上的权值解释为线路的造价.则最小生成树表示使其造价最小的生成树. 构造网的最小生成树必须解决下面两个问题: 1.尽可能选取权值小的边,但不能构成回路: 2.选取n-1条恰当的边以连通n个顶点: MST性质:假设G=(V,E)是一个连通网,U是顶点V的一个非空子集.若(