例题
农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。
约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。
为了用最小的消费,他想铺设最短的光纤去连接所有的农场。
你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。
输入格式 Input Format
输入格式经常会以两中形式
(1)采用邻接矩阵存储
第一行为农场的个数,N(3<=N<=100)。
接下去为一个N*N的矩阵,表示每个农场之间的距离。(农场之间的距离小于999,0路线表示无法直接到达)。
(2)图采用边目录方式存储。
第一行N为农场的个数,M为农场与农场之间共有M条可以搭设光纤路线。
接下去的M行为中每行有3个数A,B,C。分别表示农场A到农场B的距离为C。
输出格式 Output Format
输出连接所有农场并所用光纤最短的方案。 (输出之后要求换行)
样例输入 Sample Input
(1)采用邻接矩阵存储。 (2)采用边目录方式存储。
6 6 7
0 3 0 0 0 2 1 2 3
3 0 5 0 2 0 2 3 5
0 5 0 1 0 0 3 4 1
0 0 1 0 4 0 4 5 4
0 2 0 4 0 1 2 5 2
2 0 0 0 1 0 6 5 1
1 6 2
样例输出 Sample Output
(1)采用邻接矩阵存储 (2)采用边目录方式存储。
10 10
(1)我的prim的代码采用邻接矩阵存储
prim适合采用邻接矩阵存储代码如下
var n,i,j,w,k,t,w1,m,min,p:longint;
ch:char;
lowcost,coset:array[1..100]of longint;
bo:array[1..100]of boolean;
map:array[1..100,1..100]of longint; {邻接矩阵图}
begin
while not eof do
begin
readln(n);
if n=0 then break;
for i:=1 to n do
for j:=1 to n do //初始化
begin
read(map[i,j]);
if (i=j)or(map[i,j]=0)then
map[i,j]:=maxlongint; //把不相连的点之间设为无穷大
end;
for i:=1 to n do
begin
lowcost[i]:=map[1,i];
coset[i]:=1;
bo[i]:=false;
{初始化lowcost集合(即每个点到集合的最短距离)与bo数组和
coset(设这个点为A)到集合内于他连接的且最短距离的另一个点(这个点为b)
那么coset就是记录与点A的父亲节点B(B一定要具备上述条件)}
end;
bo[1]:=true;
m:=0;
for i:=1 to n-1 do
begin
min:=maxlongint;
for j:=1 to n do
if (bo[j]=false)and(lowcost[j]<min)then //选择与集合距离最短的点
begin
min:=lowcost[j];p:=j;
end;
writeln('(',coset[p],',',p,')'); //输出上一步得到的与集合距离啊短距离的点的父亲节点和该点(即集合新选择的最短路径);
m:=m+min; //把上一步得到的点到集合的距离不断累加
bo[p]:=true; //把以加入的集合的点设为true,防止重判.
for j:=1 to n do
if (bo[j]=false)and(map[p,j]<lowcost[j])then //重判集合到那一些还每被选入集合的点的距离
begin
lowcost[j]:=map[p,j]; //重判集合到那一些还每被选入集合的点的距离
coset[j]:=p; //刷新父亲节点
end;
end;
writeln(m);
end;
end.
(2)我的kruskal的代码采用边目录方式存储
kruskal适合采用边目录方式存储。
(kruskal的一般版本);
在这里说明一下感染和完全感染的区别以便于理解下面的代码的注释
[感染指一条边中只有一个点被感染了要么是起点,要么是始点,一边中的两点中只有一点被感染称为感染]
[完全感染染指一边中两点都被感染了,只有两点同时都被感染了才称为完全感染。如果该边的两点被完全感染那么这条边也就被完全感染(即false),而没有被完全感染的边或感染的边都为(true)]
解析的不好不要BS我水平有限
type edge=record
x,y,c:longint;
end;
var n,m,i,j,mincost,min,p:longint;
d:array[1..100] of boolean;
e:array[1..100]of boolean;
elist:array[1..100] of edge;
begin
while not eof do
begin
read(n,m);
for i:=1 to m do read(elist[i].x,elist[i].y,elist[i].c);
fillchar(d,sizeof(d),true); //读入数据加初始化
fillchar(e,sizeof(e),true);
m:=0;
for j:=1 to n-1 do
begin
min:=maxlongint;
for i:=1 to m do
if e[i]=true then
if ((d[elist[i].x]=true) xor (d[elist[i].y]=true)) or (j=1) then //选择感染了的边这样可以完全避开够成环情况(但第一条边需要开绿灯)
if (elist[i].c)<min then //对被感染了的边进行判断选择其边的值最小的
begin
min:=elist[i].c;p:=i; //记录该边的值,以及该边的起点和始点
end;
d[elist[p].x]:=false; d[elist[p].y]:=false; //把该边完全感染(即起点和始点都被感染)
writeln('(',elist[p].x,',',elist[p].y,')'); //输出新的被完全感染的边的起点和始点(既路径)
e[p]:=false; //因为起点和始点都被感染所以该边也应被完全感染
m:=m+min; //累加被完全感染的边的值
end;
writeln(m);
end;
end.
(改进后的kruskal+快排的高效率版本);
type edge=record
x,y,c:longint;
end;
var n,m,i,j,mincost:longint;
d:array[1..100] of boolean;
e:array[1..100of boolean;
elist:array[1..100] of edge;
procedure qsort(ss,tt:longint);
var i,j,x:longint;
temp:edge;
begin
i:=ss;j:=tt;x:=elist[(i+j)div 2].c;
while i<=j do
begin
while elist[i].c<x do inc(i);
while elist[j].c>x do dec(j);
if i<=j then
begin
temp:=elist[i];
elist[i]:=elist[j];
elist[j]:=temp;
inc(i);
dec(j);
end;
end;
if ss<j then qsort(ss,j);
if i<tt then qsort(i,tt);
end;
begin
while not eof do
begin
read(n,m);
for i:=1 to m do read(elist[i].x,elist[i].y,elist[i].c);
qsort(1,m);
fillchar(d,sizeof(d),true);
fillchar(e,sizeof(e),true);
mincost:=0;
for j:=1 to n-1 do
begin
for i:=1 to m do
if e[i]=true then
if ((d[elist[i].x]=true) xor (d[elist[i].y]=true)) or (j=1) then
begin
d[elist[i].x]:=false; d[elist[i].y]:=false; {高效体现在这里,和上面的那个代码比较省去了判断
writeln('(',elist[i].x,',',elist[i].y,')'); 而表面上看感觉不出如何省时,里面切暗藏玄机。
e[i]:=false; 省时在于每次选择被感染的边都是一次到位决不含糊}
mincost:=mincost+elist[i].c; //下面进行prim,kruskal算法比较会进一步说明
break;
end;
end;
writeln('tree: ','length=',mincost);
end;
end.
个人对prim算法与kruskal算法比较和总结
1 )Prim and Kruskal 算法的空间比较
数据给的情况不同空间有所不同
当点少边多的时候如1000个点500000条边这样BT的数据用prim做就要开一个1000*1000的二维数组
而用kruskal做只须开一个500000的数组,恐怖吧500000跟1000*1000比较相差一半。
当点多边少的时候如1000000个点2000条边像这中BT数据就是为卡内存而存在的,如果用prim做你想开一个1000000*1000000的二维数组没门内存绝对爆挂你。而像这种情况用kruskal只须开一个2000的数组绝对赚到了。
2 )Prim and Kruskal and Kruskal+快排 算法的时间比较
prim 在跟普通的kruskal比较空间是肯定没有普通的kruskal来的好。但时间方面的话prim就比普通kruskal来的更恐怖一些,用prim时间比普通的kruskal快20倍。在这时我就想如那数据变态的很用普通的kruskal绝对超时,用prim绝对1爆的内存那就掺了。这时惟有改进prim算法从中砍内存,怎么砍,换一个超大内存的电脑,你去那找啊。拿刀砍,开玩笑。方法一放弃。方法二在改进kruskal算法从中砍时间,经过反复的折腾最后(在老师的指导下)想到了普通的kruskal在选择感染了的边的时候还要进行搜索其所有被感染了的边中值最小的边,每一次都要在此处进行重复的搜索觉的很费时,索性事先派好序。所以改进后变为kruskal+快排,结果时间跟prim相差无几,而且有省内存。这就是王道啊。。。(回头一看啊哇靠写了好长啊,各位来访的大虾小虾,大牛小牛写的不好不要BS我哦,累了休息一下ZZZZ)
相关推荐
prim算法 Kruskal算法分别实现最小生成树
本文将详细介绍两种经典算法来解决最小生成树问题:Prim算法和Kruskal算法,并以C语言实现为例进行讲解。 ### Prim算法 Prim算法是一种贪心算法,其基本思想是从一个初始节点开始,逐步添加最短的边,直到连接到...
### 使用Prim和Kruskal算法构建最小生成树 在图论中,最小生成树(Minimum Spanning Tree, MST)是一个非常重要的概念。对于一个连通的无向图来说,如果存在一个子图,它包含原图的所有顶点,并且这些顶点通过边...
在通信网理论作业3-最小生成树这个项目中,你可能会学习如何用MATLAB编写代码,实现Prim和Kruskal算法,并对给定的网络图数据进行最小生成树的构造。这将涉及到数据结构的设计、图的遍历以及最小生成树的验证等编程...
1. **引言**:介绍最小生成树的概念,以及Prim和Kruskal算法的基本思想。 2. **算法描述**:详细解释两种算法的步骤,包括伪代码或流程图。 3. **实现细节**:展示如何用编程语言(如C++、Java或Python)实现这两种...
本文将深入探讨Prim和Kruskal两种经典的最小生成树算法。 ## Prim算法 Prim算法是一种贪心算法,它从一个起始顶点开始,逐步添加边,每次选择与当前生成树连接且权重最小的边,直到所有顶点都被包含在内。以下是...
综上所述,最小生成树是图论中的核心问题,Prim算法和Kruskal算法是解决该问题的两种高效方法。在C++中,这两个算法都可以利用标准库提供的功能来实现,从而在复杂度和空间效率上达到较好的平衡。理解并熟练掌握这些...
(1)、实验题目:给定一个地区的n 个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并得到的最小生成树的代价。 (2)、实验要求: 1、城市间的距离网采用的邻接矩阵表示,邻接矩阵的存储结构定义采用...
最小生成树(Prim、Kruskal 算法)整理版 本文档对最小生成树的概念和算法进行了详细的介绍,包括树和生成树的基本概念、最小生成树的定义和应用、Prim 和 Kruskal 算法的思想和实现。 一、树及生成树的基本概念 ...
图论中的最小生成树算法:Prim与Kruskal算法详解
### 最小生成树Kruskal算法详解 #### 算法背景与定义 最小生成树(Minimum Spanning Tree,简称MST)是图论中的一个经典问题,涉及到在一个加权图中寻找一棵包含所有顶点的子图,使得这棵子图的总权重最小。在实际...
通过上述代码示例,我们可以看到如何在Python中实现Prim算法和Kruskal算法来构建最小生成树。这些技术在实际的软件开发和数据处理中有着广泛的应用,尤其是在需要优化网络连接和降低成本的场景中。随着技术的发展,...
最小生成树是图论中的一个重要概念,特别是在计算机科学...总之,最小生成树问题是图论中的基础问题,通过Prim和Kruskal算法可以有效地解决这一问题,它们都是利用贪心策略逐步构造最优解,为实际问题提供了解决方案。
最小生成树算法是图论中的一个经典问题,用于寻找连接所有顶点的边最少的树结构,这在很多实际场景中都有应用,如构建通信网络、优化交通路线等。在这个压缩包中,包含了两种最常用的最小生成树算法的实现:Prim算法...
详细的c语言实现最小生成树的prim算法和kruskal算法,非常有用的
根据给定文件的信息,本文将深入探讨两种构造最小生成树的经典算法——普里姆(Prim)算法与克鲁斯卡尔(Kruskal)算法,并通过具体的代码实现来展示这两种算法的应用场景与实现细节。 ### 一、最小生成树概念 #### ...
要解决最小生成树问题,两种著名的贪心算法——Prim算法和Kruskal算法被广泛采用。这两种算法都是基于贪心策略,即在每一步中选择当前最优的选择,以期最终达成全局最优解。 **Prim算法**的核心在于从某个顶点开始...
最小生成树是图论中的一个重要概念,用于...总的来说,Prim和Kruskal算法是解决最小生成树问题的两种经典方法,它们都基于贪心策略,但实现细节有所不同。掌握这两种算法及其C++实现对于理解和解决图论问题至关重要。
4. 当最小生成树集合包含了n-1条边时(n为顶点数),算法结束,最小生成树构建完成。 在MATLAB中,我们可以用以下步骤来实现这个算法: 1. 创建一个邻接矩阵或邻接表来表示图。邻接矩阵是一个二维数组,其中的每个...