最小生成树的课程设计.docx

上传人:b****6 文档编号:5110449 上传时间:2022-12-13 格式:DOCX 页数:18 大小:265.67KB
下载 相关 举报
最小生成树的课程设计.docx_第1页
第1页 / 共18页
最小生成树的课程设计.docx_第2页
第2页 / 共18页
最小生成树的课程设计.docx_第3页
第3页 / 共18页
最小生成树的课程设计.docx_第4页
第4页 / 共18页
最小生成树的课程设计.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

最小生成树的课程设计.docx

《最小生成树的课程设计.docx》由会员分享,可在线阅读,更多相关《最小生成树的课程设计.docx(18页珍藏版)》请在冰豆网上搜索。

最小生成树的课程设计.docx

最小生成树的课程设计

数据结构与算法

课程设计报告

课程设计题目:

构造可以使n个城市连接的最小生

成树

专业班级:

信息与计算科学1001班

姓名:

学号:

设计室号:

理学院机房

设计时间:

2011-12-26批阅时间:

指导教师:

成绩:

构造可以使n个城市连接的最小生

成树

主要任务:

给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。

设计该程序的基本要求:

1、城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值。

要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。

2、表示城市间距离网的邻接矩阵(要求至少6个城市,10条边)

3、最小生成树中包括的边及其权值,并显示得到的最小生成树的代价。

 

总体设计

《1》该程序的主要功能:

能实现根据输入城市的信息可以判断该城市间的距离网是否构成最小生成树,遍历城市生成最小生成树,通过计算得到最小生成树的代价。

《2》该城市间的距离网用邻接矩阵表示

《3》用克鲁斯卡尔(Kruskal)算法建立最小生成树

 

详细设计说明

《1》该程序的主要功能:

能实现根据输入城市的信息可以判断出该城市间的距离网是否构成最小生成树,遍历城市生成最小生成树,通过计算得到最小生成树的代价。

该程序的模块结构功能图及主要函数如下:

 

a)intmain()//主程序

b)intmenu()//菜单函数

c)voidcreate()//输入城市信息函数

d)voidjudge()//判断是否能够生成最小生成树函数

e)voiddisplay()//打印输出

f)voidset()//初始化pre[],rank[]函数

g)voidfind()//判断是否构成回路函数

h)voidUnion()//将能构成最小生成树的边添加到一个集合

l)voidKrushal()//克鲁斯算法求最小生成树

体会

确定程序功能设计出总体流程对整个设计进行非常重要,明确要完成设计需要的程序算法,为整个设计流程划出大纲,可以使整个设计思路更加简单明了。

《2》构造结构体

本题为求最小生成树,先要构造一个结构体,再用邻接矩阵的形式表现出来。

#definemax20

#defineMAX_LNT10

typedefstructnode/*构造一个结构体,两个城市可以看成起点和终点,之间的道路可以看成一个边*/

{

intstr;/*起点*/

intend;/*终点*/

intdis;/*距离*/

}node;

nodep[max],temp;/*p记录城市信息*/

intpre[100],rank[100];/*用于判断是否构成回路*/

intn=0,arcs[MAX_LNT][MAX_LNT];/*n表示城市个数,arcs[][]记录城市间权值*/

《3》初始化

voidset(intx)/*初始化*/

{

pre[x]=x;

rank[x]=0;

}

intfind(intx)/*找到这个点的祖先*/

{

if(x!

=pre[x])

pre[x]=find(pre[x]);

returnpre[x];

}

voidUnion(intx,inty)/*将这两个添加到一个集合里去*/

{

x=find(x);

y=find(y);

if(rank[x]>=rank[y])

{

pre[y]=x;

rank[x]++;

}

elsepre[y]=x;

}

该城市间的距离网使用邻接矩阵表示,邻接矩阵存储方法(数组存储方法),利用两个数组来存储一个图。

用a[i][j]数组,利用邻接矩阵方式来储存城市与城市间信息。

voidcreate()/*输入城市信息*/

{

inti,j;

printf("请输入城市的个数:

\n");

scanf("%d",&n);

printf("输入%d个城市的邻接矩阵:

\n",n);

for(i=1;i<=n;i++)

{

for(j=1;j<=n;j++)

scanf("%d",&arcs[i][j]);

}

}

 

《3》算法设计

(1)克鲁斯卡尔算法思想基本描述:

假设连通图N=(V,{E}),则令最小生成树的初始状态为只有n顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。

在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。

以此类推,直至T中所有顶点都在同一个连通分量上为止。

(2)克鲁斯卡尔算法设计

a.设置计数器E,初值为0,记录已选中的边数。

将所有边从小到大排序,存于p[]中。

b.从p[]中选择一条权值最小的边,检查其加入到最小生成树中是否会构成回路,若是,则此边不加入生成树;否则,加入到生成树中,计数器E累加1。

c.从E中删除此最小边,转b继续执行,直到k=n-1,算法结束

d.判断是否构成回路的方法:

voidKruskal()

{

intans=0,i,j,k=0;/*ans用来记录生成最小树的权总值*/

intindex;

intcount=0;/*记录打印边的条数*/

for(i=1;i<=n;i++)/*初始化数组pre[x],rank[x]*/

set(i);

for(i=1;i<=n;i++)

{

for(j=i+1;j<=n;j++)

{

p[++k].str=i;

p[k].end=j;

p[k].dis=arcs[i][j];/*先把所有城市之间的路段看成一个边*/

}

}

for(i=1;i<=k;i++)/*把所有的边按从小到大进行排序*/

{

index=i;

for(j=i+1;j<=k;j++)if(p[j].dis

temp=p[index];

p[index]=p[i];

p[i]=temp;

}

for(i=1;i<=k;i++)

{

if(find(p[i].str)!

=find(p[i].end))/*如果这两点连接在一起不构成一个回路,则执行下面操作*/

{

printf("\t第%d条路段为:

%d--%d,权值为%d\n",++count,p[i].str,p[i].end,p[i].dis);/*将这条边的起点、终点打印出来*/

ans+=p[i].dis;/*说明这条路段要用*/

Union(p[i].str,p[i].end);

}

}

printf("\t遍历所有城市得到最小生成树的代价为:

%d\n\n",ans);

}

设置集合S,其中存放已加入到生成树中的边所连接的顶点集合,当一条新的边要加入到生成树中时,检查此边所连接的两个顶点是否都已经在S中,若是,则表示构成回路,否则,若有一个顶点不在S中或者两个顶点都不在S中,则不够成回路。

voidjudge()/*判断是否能够生成最小生成树*/

{

intclose[100],low[100],i,j,ans=0;/*close[j]表示离j最近的顶点,low[j]表示离j最短的距离*/

intuse[100];

use[1]=1;

for(i=2;i<=n;i++)

{

low[i]=arcs[1][i];/*初始化*/

close[i]=1;

use[i]=0;

}

for(i=1;i

{

intmin=100000000,k=0;

for(j=2;j<=n;j++)

{

if(use[j]==0&&min>low[j])/*找到最小的low[]值,并记录*/

{

min=low[j];

k=j;

}

}

for(j=2;j<=n;j++)

{

if(use[j]==0&&low[j]>arcs[k][j])

{

low[j]=arcs[k][j];/*修改low[]值和close[]值*/

close[j]=k;

}

}

ans+=arcs[close[k]][k];

}

if(ans>=100000000)printf("不能构成最小生成树\n");

elseprintf("能构成最小生成树\n");

}

克鲁斯卡尔算法(Kruskal'salgorithm)是两个经典的最小生成树算法的较为简单理解的一个。

这里面充分体现了贪心算法的精髓。

克鲁斯卡尔算法生成最小生成树的过程

(3)防止不能构成最小生成树的图

为避免输入的图构成的不是连通图,设计了judge()函数来判断输入数据构成的是否为连通图,此函数的主要算法是源于普里姆(PRIM)算法,经过改编,形成了新的函数。

《4》主函数的设计

intmain()/*主函数*/

{

while

(1)

{

switch(menu())

{

case1:

create();break;/*输入城市信息*/

case2:

judge();break;/*判断是否能够生成最小生成树*/

case3:

display();break;/*显示生成的最小生成树*/

case4:

exit(0);

}

}

return0;

}

调试与测试

 

以一个6个城市、10条边的网络图为例进行测试

16

20115

196

22149

18

网络图

GE=

邻接矩阵

 

生成界面

输入城市间信息

判断是否生成最小生成树

 

遍历所有城市最小生成树

退出

程序源代码

#include

#include

#include

#definemax20

#defineMAX_LNT10

typedefstructnode/*构造一个结构体,两个城市可以看成起点和终点,之间的道路可以看成一个边*/

{

intstr;/*起点*/

intend;/*终点*/

intdis;/*距离*/

}node;

nodep[max],temp;/*p记录城市信息*/

intpre[100],rank[100];/*用于判断是否构成回路*/

intn=0,arcs[MAX_LNT][MAX_LNT];/*n表示城市个数,arcs[][]记录城市间权值*/

intmenu()/*菜单函数*/

{

intm;

printf("..........................2011年12月29日......................\n\n");

printf("求最小生成树\n");

printf("________________________________\n\n");

printf("1输入城市之间的信息\n");

printf("2判断是否能构成一个最小生成树\n");

printf("3遍历所有城市生成最小生成树\n");

printf("4退出\n");

printf("________________________________\n\n");

printf("请输入所选功能1-4\n");

system("colorA");/*改变界面颜色的,对程序没什么影响*/

scanf("%d",&m);

returnm;

}

 

/*下面三个函数作用是检验当一条边添加进去,是否会产生回路*/

voidset(intx)/*初始化*/

{

pre[x]=x;

rank[x]=0;

}

intfind(intx)/*找到这个点的祖先*/

{

if(x!

=pre[x])

pre[x]=find(pre[x]);

returnpre[x];

}

voidUnion(intx,inty)/*将这两个添加到一个集合里去*/

{

x=find(x);

y=find(y);

if(rank[x]>=rank[y])

{

pre[y]=x;

rank[x]++;

}

elsepre[y]=x;

}

voidKruskal()

{

intans=0,i,j,k=0;/*ans用来记录生成最小树的权总值*/

intindex;

intcount=0;/*记录打印边的条数*/

for(i=1;i<=n;i++)/*初始化数组pre[x],rank[x]*/

set(i);

for(i=1;i<=n;i++)

{

for(j=i+1;j<=n;j++)

{

p[++k].str=i;

p[k].end=j;

p[k].dis=arcs[i][j];/*先把所有城市之间的路段看成一个边*/

}

}

for(i=1;i<=k;i++)/*把所有的边按从小到大进行排序*/

{

index=i;

for(j=i+1;j<=k;j++)if(p[j].dis

temp=p[index];

p[index]=p[i];

p[i]=temp;

}

for(i=1;i<=k;i++)

{

if(find(p[i].str)!

=find(p[i].end))/*如果这两点连接在一起不构成一个回路,则执行下面操作*/

{

printf("\t第%d条路段为:

%d--%d,权值为%d\n",++count,p[i].str,p[i].end,p[i].dis);/*将这条边的起点、终点打印出来*/

ans+=p[i].dis;/*说明这条路段要用*/

Union(p[i].str,p[i].end);

}

}

printf("\t遍历所有城市得到最小生成树的代价为:

%d\n\n",ans);

}

voidcreate()/*输入城市信息*/

{

inti,j;

printf("请输入城市的个数:

\n");

scanf("%d",&n);

printf("输入%d个城市的邻接矩阵:

\n",n);

for(i=1;i<=n;i++)

{

for(j=1;j<=n;j++)

scanf("%d",&arcs[i][j]);

}

}

voiddisplay()/*显示生成的最小生成树*/

{

if(n==0)

{

printf("这里没有城市之间的信息\n");

return;

}

printf("遍历所有城市得到最小生成树为:

\n\n\n");

Kruskal();

}

 

voidjudge()/*判断是否能够生成最小生成树*/

{

intclose[100],low[100],i,j,ans=0;/*close[j]表示离j最近的顶点,low[j]表示离j最短的距离*/

intuse[100];

use[1]=1;

for(i=2;i<=n;i++)

{

low[i]=arcs[1][i];/*初始化*/

close[i]=1;

use[i]=0;

}

for(i=1;i

{

intmin=100000000,k=0;

for(j=2;j<=n;j++)

{

if(use[j]==0&&min>low[j])/*找到最小的low[]值,并记录*/

{

min=low[j];

k=j;

}

}

for(j=2;j<=n;j++)

{

if(use[j]==0&&low[j]>arcs[k][j])

{

low[j]=arcs[k][j];/*修改low[]值和close[]值*/

close[j]=k;

}

}

ans+=arcs[close[k]][k];

}

if(ans>=100000000)printf("不能构成最小生成树\n");

elseprintf("能构成最小生成树\n");

}

 

intmain()/*主函数*/

{

while

(1)

{

switch(menu())

{

case1:

create();break;/*输入城市信息*/

case2:

judge();break;/*判断是否能够生成最小生成树*/

case3:

display();break;/*显示生成的最小生成树*/

case4:

exit(0);

}

}

return0;

}

 

WelcomeTo

Download!

!

!

 

欢迎您的下载,资料仅供参考!

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 军事

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1