当前位置:文档之家› 云南大学数学系《运筹学通论》课程上机实验报告

云南大学数学系《运筹学通论》课程上机实验报告

一.实验目的
通过使用prim算法(反圈法)求解最小支撑树问题.
二.实验内容
设图G =(V,E),其生成树的顶点集合为U。

①.把v0放入U。

②.在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成
树。

③.把②找到的边的v加入U集合。

如果U集合已有n个元素,则结束,否
则继续执行②。

其算法的时间复杂度为O(n^2)
Prim算法实现:
图用邻接阵表示,路径不通用无穷大表示,在计算机中可用一个大整数代
替。

采用堆,可以将复杂度降为O(m log n),如果采用Fibonaci堆可以将
复杂度降为O(n log n + m)
三.使用环境
Windows XP 环境下C语言编写
四.调试过程
程序如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INFINITY 1000
#define max_name 50
#define max_vertex_num 50
typedef char vertex[max_name];//顶点名字串
typedef int adjMatrix[max_vertex_num][max_vertex_num];//邻接距阵
typedef struct
{vertex adjvex; //邻接矩阵
int lowcost; //权值
}close[max_vertex_num];//定义一个结构以便在后面closedge 使用
typedef struct//定义图
{
vertex vexs[max_vertex_num]; //顶点集
adjMatrix arcs; //边
int vexnum,arcnum;//点个数,边个数
}MGraph;
int LocateVex(MGraph G,vertex u)//若G中存在顶点u,则返回该点在图中位置;
否则返回其他信息;
{
int i;
for(i=0;i<G.vexnum;++i)
if(strcmp(u,G.vexs[i])==0)
return i;
return 1;
}
void CreateGraph(MGraph &G)
{
int i,j,k,w;
vertex v1,v2;
printf("输入无向图顶点数和边数: \n");
scanf("%d %d",&G.vexnum,&G.arcnum);
printf("输入各顶点的值:\n", G.vexnum);
for(i=0;i<G.vexnum;++i) //构造顶点集
scanf("%s",&G.vexs[i]);
for(i=0;i<G.vexnum;++i) //初始化邻接方阵
for(j=0;j<G.vexnum;++j)
G.arcs[i][j]=INFINITY;
printf("输入一条边依附的顶点及权值:\n",G.arcnum);//输入一条边依附的顶
点及权值
for(k=0;k<G.arcnum;++k)
{
scanf("%s%s%d",v1,v2,&w);
i=LocateVex(G,v1);//v1在图中位置
j=LocateVex(G,v2);//v2在图中位置
G.arcs[i][j]=G.arcs[j][i]=w; //置于对称弧
}
}
int minimum(close c,MGraph G)//求出下一个节点第k个顶点
{
int i=0,j,k,min;
min=INFINITY;
//初始化
k=-1;
for(j=0;j<=G.vexnum;j++)//求最小
if(c[j].lowcost<min&&c[j].lowcost>0)
{
min=c[j].lowcost;
k=j;
}
return k;
}
void PRIM(MGraph G,vertex u)
{
int i,j,k=0;
close closedge;//一个结构
bool isbreak=false;
k=LocateVex(G,u);//u在图中位置返回G.vexs[i]中下标
for(j=0;j<=G.vexnum;++j) //辅助数组初始化closedge从O 开始
{
if(j!=k)//没有自己到自己的
closedge[k].lowcost=0;
strcpy(closedge[j].adjvex,u);
closedge[j].lowcost=G.arcs[k][j];//列
}
int flag[1000];
flag[0]=0;
int count=1;
for(i=1;i<G.vexnum;++i)
{
k=minimum(closedge,G);
if(k==-1)
{
isbreak=true;
break;
}
printf("%s-%s%d\n",closedge[k].adjvex,G.vexs[k],G.arcs[k][LocateVex(G,closedg
e[k].adjvex)]); //输出生成树的边
closedge[k].lowcost=0; // 第k个顶点并入U集
flag[count]=k;
count++;
for(j=0;j<G.vexnum;++j)
if(G.arcs[k][j]<closedge[j].lowcost)//新顶点并入U后重新选择最小边
{
strcpy(closedge[j].adjvex,G.vexs[k]);
closedge[j].lowcost=G.arcs[k][j];
}
}
if(isbreak)
{
printf("此图不连通,无最小支撑树!\n访问过的点为:\n");
for(i=0;i<count;i++)
{
printf("%s ",G.vexs[flag[i]]);
}
printf("\n");
}
}
void main()
{
MGraph G;
CreateGraph(G);
printf("最小生成树的各条边为: \n");
PRIM(G,G.vexs[0]);
}
五.实验结果
此处給出两个赋权图, 用prim算法找出赋权图上的最小树.
图1结果如下
:
注释 :图1中有7个点10条边, 最后结果输出最小生成树为:
图1最小权值W=5+1+2+3+4+1= 16
1133 2
5
4
6
6 5
2
4
1
3 1 图1.
7
1 1133 2
5
4 6
6 5
2
4
4
1 7
3
1 图1.
7
1
图2结果如下
:
注释:图2中有7个点10条边,但较图1相比图2中(4-5)(5-6)无边相連,固输入权值为0.
所以结果出现了两个連通子图.整个图2不連通,无最小支撑
树. 结果如下:
六.实验总结1
1
3
3
2
5
4
6
5
2
1 3
1 7
1
图2 1
1
3
3
2
5
4
6
6
5
2
1
7
3
1 7
1
图2
1.无向图的生成树就是从图的边集中选择一些边,使得这些边构成一个连通无环图,也就是树。

如果给每一条边加一个权,所有生成树中权和最小的生成树称为最小生成树。

普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法是利用MST性质构造最小生成树的算法.此次实验图的存储用的是邻接矩阵的形式.Prim算法的解答结果有时候不是唯一的,例如在此次实验中
(4-6)(5-6)两条边权值都等于4,但由于输入的顺序,最后打印的结果是(4-6)这个条边组成的边,其实包含(5-6)这条边的最小支撑树也是正确的结果.所以结果和对图遍历时的顺序有关,但是必须注意的是所有的最小生成树其网络代价和是一样的.
2.实验中由于以前在<<数据结构>>课程中学过給定连通图算法实现最小支撑树,后来变化了要求,如果一开始給出的是不连通图,我的程序就实现不了了, 但此程序是基于连通来写的,后来调程序废了很多时间,想了一些办法,最后在k=LocateVex(G,u)这里找到突破口,打印出了遍历的结果.
3.在实验中出现了很多错误,例如对C++不熟悉,在进行编译以前就出错。

一些初值
也出现了错误.后来改正了错误.
4.加强理论学习和上机实践,感觉两方面自己都做的不好,望今后能做的更好些。

相关主题