最小生成树实验

一、实验目的

1.进一步掌握图的结构及非线性特点,递归特点和动态性。

2.进一步巩固最小生成树的两种求解算法。

二、实验原理

从任意一顶点 v0 开始选择其最近顶点 v1 构成树 T1,再连接与 T1 最近顶点 v2 构成树 T2, 如此重复直到所有顶点均在所构成树中为止。

最小生成树(MST):权值最小的生成树。

生成树和最小生成树的应用:要连通n个城市需要n-1条边线路。可以把边上的权值解释为线路的造价。则最小生成树表示使其造价最小的生成树。

构造网的最小生成树必须解决下面两个问题:

1、尽可能选取权值小的边,但不能构成回路;

2、选取n-1条恰当的边以连通n个顶点;

MST性质:假设G=(V,E)是一个连通网,U是顶点V的一个非空子集。若(u,v)是一条具有最小权值的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树。

prim算法假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:

在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。

此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。

 Prim算法的核心:始终保持TE中的边集构成一棵生成树。

注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图

三、参考程序

#include<stdio.h>
#define max 7
int quan[max][max];//放权值
int useing[max],used[max];//useing表示已经被选中的节点,used表示未被选中的节点
struct biao{
int index;
int quanzhi;
}b[max-1];//用来存放quanzhi数组中某一行的数据,
void tree(){
int min=1000,j,miny,minx=1,i=0,k,uing=1,ud=1,count=0,z,t=0,w=0;
//min=1000表示路不通。 minx表示第几行,miny 表示第几列,count用来计算总的最小权值
while(true){
i=minx;
useing[uing]=i;//把被选中的节点给useing我们从1节点开始
uing++;
for(k=1;k<max;k++){
if(minx==used[k]){
used[k]=1000;//如果节点亦被选中把该位置=1000

}
}


printf("\n i--%d\n",i);
for(k=1, j=1;j<max;j++,k++){//给b数组初始化
b[k].index=j;//下表给它
b[k].quanzhi=quan[i][j];//权值给他

}//for
min=1000;
for(k=1;k<max;k++){//寻找与该节点相连的权值最小的那个节点
if(min>b[k].quanzhi){
min=b[k].quanzhi;
miny=k;//记录下该节点的下表
}
}

quan[i][miny]=1000;
quan[miny][i]=1000; //把找到的节点的数=1000;
printf("\n---1---\n");

/*

printf("\n min--%d\n",min);
printf("\n minx--%d\n",minx);
for(i=1;i<max;i++){
printf("%d\t",b[i].quanzhi);
}
printf("\n");
for(i=1;i<max;i++){
for(j=1;j<max;j++)
printf("%d\t",quan[i][j]);
printf("\n");
}
*/

minx=miny;//把找到的节点的下表给minx,为了便利找到该节点的最小权值
z=0;
for(i=1;i<max;i++){
if(miny==useing[i]){//形成环路了
z=1;
w=1;

}

}
if(z==1){
for(i=1;i<max;i++){//从还未 被赵国的节点再次开始开始
if(used[i]!=1000){
minx=used[i];//把未被选中过的下标给minx

used[i]=1000;//并把used该位置=1000
break;
}
}
}

// useing[uing]=minx;
// printf("\n using--%d\n",uing);
// uing++;




count=count+min;//求最小权值总和
// printf("\n--count-%d---\n",count);
if(t==6)//结束循环,
break;
t=0;
for(i=1;i<max;i++){//判断所有顶点是否全被便利过
if(used[i]==1000){
t++;
}

}
if(w==1){//减去那个形成环路时多加的权值
count=count-min;

}
w=0;

}
for(i=1;i<max;i++){
printf("%d\t",useing[i]);
}
printf("\n");
for(i=1;i<max;i++){
printf("%d\t",used[i]);
}
printf("\n");

printf("\n--count1-%d---\n",count);
}


int main(){
int i,j,t=0,number,weight;;
for(i=0;i<max;i++){
for(j=0;j<max;j++)
quan[i][j]=1000;
}
for(i=0;i<max;i++){
used[i]=i;
useing[i]=0;
}

FILE *fr;

fr = fopen("D:\\123.txt","r");
if(!fr)
{
printf("fopen failed\n");
}
while(fscanf(fr,"%d%d%d", &i, &j, &weight) != EOF)
{
quan[i][j] = weight;
quan[j][i] = weight;
}

for(i=1;i<max;i++){
for(j=1;j<max;j++)
printf("%d\t",quan[i][j]);
printf("\n");
}
for(i=1;i<max;i++){
printf("%d\t",useing[i]);
}

for(i=1;i<max;i++){
printf("%d\t",used[i]);
}
tree();
return 0;

}

转载于:https://www.cnblogs.com/huifeidezhuzai/p/9278962.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值