最小生成树算法实验报告

时间:2024.3.20

最小生成树算法

Ø  问题描述

设G=(V,E)是一个无向连通带权图,E中每条边(v,w)的权为c(v,w)。如果G的一个子图G`是一棵包含G的所有顶点的书,则称G`为G的生成树。生成树上各边权的总和称为该生成树的耗费,在G的所有生成树中,耗费最小的生成树就称为G的最小生成树。给定一个无向连通带权图,构造一个最小生成树。

Ø  设计思想

利用Prim算法求最小生成树,Prim算法是利用贪心策略设计的算法。设G=(V,E)是一个连通带权图,V={1,2,…,n}。构造G的一棵最小生成树的Prim算法的基本思想是:首先置U={1},然后,只要U是V的真子集,就做如下的贪心选择:选取满足条件i∈U,j∈V-U,且使c(i,j)达到最小的边(i,j),并将顶点j添加到U中。这个过程一致进行到U=V时为止。在这个过程中选取到的所有边恰好构成G的一棵最小生成树。

Ø  时间复杂度

Prim算法的Pascal语言描述如下:

Procedure PRIM(c:array[1..n,1..n] of real);

Var

       lowcost:array[1..n] of real;

       closest:array[1..n] of integer;

       i,j,k,min,integer;

begin

(1)  for i:=2 to n do

(2)  begin{初始化,此时U只含有顶点1}

(3)     lowcost[i]:=c[1,i];

(4)     Closest[i]:=1;

(5)  end;

(6)  for i:=2 to n do

(7)  begin {寻找顶点分别在V-U与U中边权最小的边}

(8)     min:=lowcost[i];

(9)     j:=i;

(10)   For k:=2 to n do

(11)     If lowcost[k]<min then

(12)        Begin

(13)           Min:=lowcost[k];

(14)           j:=k;

(15)         End;

(16)     print(j,closest[j]);{输出找到的边}

(17)     Lowcost[j]:=∞;{将j添加到U}

(18)    For k:=2 to n do {调整lowcost和closest}

(19)    if(c[j,k]<lowcost[k])and(lowcost[k]< ∞)then

(20)        Begin

(21)           Lowcost[k]:=c[j,k];

(22)           Closest[k]:=j;

(23)        End

(24) End

(25)End;{PRIM}

上述过程中第(6)~(24)行的for循环要执行n-1次,每次执行时,第(10)~(15)行和第(18)~(23)行的for循环都要O(n)时间,所以Prim算法所需的计算时间为O(n)。

Ø  实验源代码

图定义头文件Graph.h:

const int MaxV=10;//最多顶点数

const int MaxValue=99;//最大权值

//定义边集数组中的元素类型

struct RCW

{int row,col;

 int weight;

};

class adjMList

{

private:

  int numE;//当前边数

  int GA[MaxV][MaxV];//定义邻接矩阵

public:

  //构造函数,初始化图的邻接矩阵与边集数组

  adjMList(RCW GE[],int n,int e);

  //建立无向带权图的邻接矩阵

  void CreateMatrix(int n,int &e,RCW r[]);

  //输出边集数组中的每条边

  void OutputEdgeSet(RCW ge[],int e);

  //根据图的邻接矩阵生成图的边集数组

  void ChangeEdgeSet(RCW GE[],int n,int e);

  //按升序排列图的边集数组

  void SortEdgeSet(RCW GE[],int e);

  //利用普里姆算法从顶点v0出发求出用邻接矩阵GA表

  //示的图的最小生成树,最小生成树的边集存于数组CT中

  void Prim(RCW CT[],int n);

  //检查输入的边序号是否越界,若越界则重输

  void Check(int n, int& i, int& j);

};

图实现文件Graph.cpp

//20052381 杨松 Graph.cpp

#include"Graph.h"

//构造函数,初始化图的邻接矩阵与边集数组

adjMList::adjMList(RCW GE[],int n,int e)

{int i,j;

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

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

  if(i==j) GA[i][j]=0;

  else GA[i][j]=MaxValue;

 for(i=0;i<e;i++) GE[i].weight=0;

 numE=0;

}

//输出边集数组中的每条边

void adjMList::OutputEdgeSet(RCW ge[],int e)

{int i,k=0;

 cout<<"{";

 for(i=0; i<=e-2; i++)

  if(ge[i].weight>0){k++;

   cout<<'('<<ge[i].row<<','<<ge[i].col;

   cout<<','<<ge[i].weight<<") ";

   if(k%5==0) cout<<endl;}

  if(e>0&&ge[i].weight>0) {

   cout<<'('<<ge[e-1].row<<','<<ge[e-1].col;

   cout<<','<<ge[e-1].weight<<')';}

   cout<<'}'<<endl;

}

//建立无向带权图的邻接矩阵

void adjMList::CreateMatrix(int n,int &e,RCW r[])

{int i,j,k=0,w;

 cout<<"依次输入无向带权图的每条边的起点和终点"<<endl;

 cout<<"序号及权值!直到输入权值为0的边为止!"<<endl;

 do {i=r[k].row;j=r[k].col;w=r[k].weight;

     //cin>>i>>j>>w;

     Check(n,i,j);

     if(k==e-1) break;

     GA[i][j]=GA[j][i]=w;k++;

   }while(1);

 numE=e=k;

 cout<<"邻接矩阵:\n";

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

 {for(j=0;j<n;j++)

   cout<<setw(4)<<GA[i][j];

   cout<<endl;}

}

//检查输入的边序号是否越界,若越界则重输

void adjMList::Check(int n, int& i, int& j)

{while(1) {

   if(i<0 || i>=n ||j<0 || j>=n)

    cout<<"输入有误,请重输!";

   else return;

  cin>>i>>j;}

}

//根据图的邻接矩阵生成图的边集数组

void adjMList::ChangeEdgeSet(RCW GE[],int n,int e)

{//假定只考虑无向图的情况

 int i,j,k=0;

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

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

  if(GA[i][j]!=0 && GA[i][j]!=MaxValue)

   {if(k==e) {cout<<"数组GE下标越界!\n";

     exit(1);}

    GE[k].row=i;

    GE[k].col=j;

    GE[k].weight=GA[i][j];

    k++;

   }

}

//按升序排列图的边集数组

void adjMList::SortEdgeSet(RCW GE[],int e)

{int i,j;

 RCW x;

 for(i=1; i<=e-1; i++)

  {x=GE[i];

   for(j=i-1; j>=0; j--)

    if(x.weight<GE[j].weight) GE[j+1]=GE[j];

    else break;

   GE[j+1]=x;

  }

}

//利用普里姆算法从顶点v0出发求出用邻接矩阵GA表示

//的图的最小生成树,最小生成树的边集存于数组CT中

void adjMList::Prim(RCW CT[],int n)

{int i,j, k, min, t, m, w;

  //给CT赋初值,对应为v0依次到其余各顶点的边

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

  {CT[i].row=0;

   CT[i].col=i+1;

   CT[i].weight=GA[0][i+1];}

   //进行n-1次循环,每次求出最小生成树中的第k条边

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

  {//从CT[k-1]~CT[n-2]中查找最短边CT[m]

   min=MaxValue;

   m=k-1;

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

    if(CT[j].weight<min) {

     min=CT[j].weight;

     m=j;}

  //把最短边对调到第k-1下标位置

  RCW temp=CT[k-1];

  CT[k-1]=CT[m];

  CT[m]=temp;

  //把新并入最小生成树T中的顶点序号赋给j

  j=CT[k-1].col;

  //修改有关边,使T中到T外的每一个顶点各保持

  //一条到目前为止最短的边

  for(i=k; i<n-1; i++) {

   t=CT[i].col;

   w=GA[j][t];

   if(w<CT[i].weight) {

    CT[i].weight=w;

    CT[i].row=j;

}}}}

主程序文件 Test.cpp:

//图的相关运算的测试graph2M.cpp

#include<iostream.h>

#include<iomanip.h>

#include<stdlib.h>

#include "Graph.cpp"

void main()

{

 RCW rcw[20]={{0,1,50},{1,0,50},{0,2,60},{2,0,60},

  {1,3,65},{3,1,65},{1,4,40},{4,1,40},{2,3,52},

  {3,2,52},{2,6,45},{6,2,45},{3,4,50},{4,3,50},

  {3,5,30},{5,3,30},{3,6,42},{6,3,42},{4,5,70},{5,4,70}};

 int n,k;//定义图的点数及边数等

 cout<<"输入图的点数n=";cin>>n;

 cout<<"输入图的边数k=";cin>>k;

 static RCW AE[30],BE[30];//定义边集数组

 adjMList A(AE,n,k);

 A.CreateMatrix(n,k,rcw);

 cout<<"输出边集数组中的每条边:\n";

 A.ChangeEdgeSet(AE,n,k);

 A.OutputEdgeSet(AE,k);

 cout<<"输出按升序排列的图的边集数组:\n";

 A.SortEdgeSet(AE,k);

 A.OutputEdgeSet(AE,k);

 A.Prim(BE,n);

 cout<<"输出最小生成树的边集数组:\n";

 A.OutputEdgeSet(BE,k);

 cin.get();cin.get();}

Ø  实验数据

在主程序中直接构造图的边表如下,

   {0,1,50},{1,0,50},{0,2,60},{2,0,60},

  {1,3,65},{3,1,65},{1,4,40},{4,1,40},{2,3,52},

  {3,2,52},{2,6,45},{6,2,45},{3,4,50},{4,3,50},

  {3,5,30},{5,3,30},{3,6,42},{6,3,42},{4,5,70},{5,4,70}

共7个顶点,10条边

Ø  实验结果


第二篇:最小生成树的Kruskal算法实验报告


大连民族学院

计算机科学与工程学院实验报告

实验题目:     最小生成树的Kruskal算法                                   

课程名称:       离散数学                                 

实验类型:□演示性  □验证性  □操作性  设计性  □综合性

专业:软件工程  班级:111    学生姓名:xx     学号:xx   

实验日期:20##年12月6-28日   实验地点:金石滩校区机房201

实验学时: 10学时             实验成绩:

指导教师: 焉德军  姜楠   20##年 12月28 日

[实验原理]

  设所给定无向连通加权图具有n个结点,m条边,首先,将各条边的权按从小到大的顺序排序。然后依次将这些边按所给图的结构放到生成树中去。如果在放置某一条边时,使得生成树形成回路,则删除这条边。这样,直至生成树具有n-1条边时,我们所得到的就是一棵最小生成树。

[实验内容]

  给定无向连通加权图,编程设计求出其一棵最小生成树。

[实验目的]

  通过算法设计并编程实现求出给定无向连通加权图的一棵最小生成树,加深学生对求最小生成树的Kruskal算法的理解。

[实验步骤]

(1)  边依小到大顺序得l1,l2,…,lm

(2)  置初值:S,0i,1j。

(3)  若i=n-1,则转(6)。

(4)  若生成树边集S并入一条新的边lj之后产生的回路,则j+1j,并转(4)。

(5)  否则,i+1i;ljS(i);j+1j,转(3)。

(6)  输出最小生成树S。

(7)  结束。

具体程序的C++实现如下:

#include <iostream>

using namespace std;

const int MaxVertex = 20;

const int MaxEdge = 100;

const int MaxSize = 100;

struct EdgeType

{

         int from;

         int to;

         int weight;

};

struct EdgeGraph

{

         char vertex[MaxVertex];

         EdgeType edge[MaxEdge];

         int vertexNum;

         int edgeNum;

};

int FindRoot(int parent[], int v);    

void InputInfo();

void Kruskal(EdgeGraph G)

{

         int vex1,vex2,f,t;

         int i,num;

         int parent[MaxVertex];

         for(i=0; i<G.vertexNum; i++)

         {

                   parent[i] = -1;

         }

         for(num =0,i=0; i<G.edgeNum; i++)

         {

                   vex1 = FindRoot(parent, G.edge[i].from);

                   vex2 = FindRoot(parent, G.edge[i].to);

                   if(vex1 != vex2)

                   {

                            cout << "(" << G.edge[i].from << "," << G.edge[i].to << ")" << endl;

                            f = G.edge[i].from;

                            t = G.edge[i].to;

                            cout << "(" << G.vertex[f] << "," << G.vertex[t] << ")" << " Weight: " << G.edge[i].weight << endl;

                            cout << endl;

                            parent[vex2] = vex1;

                            num++;

                            if(num == G.vertexNum-1) return;   

                   }

         }

         return;

}

int FindRoot(int parent[], int v)

{

         int t;

         t = v;

         if(parent[t] > -1)

         {

                   t = parent[t];

         }

         return t;

}

void InputInfo()

{

         EdgeGraph G;

         cout << "Please input vertexNum , edgeNum: " << endl;

         cin >> G.vertexNum >> G.edgeNum;

         cout << "Please input the information of edges:" << endl;

         for(int i=0; i<G.vertexNum; i++)

         {

                   cin >> G.vertex[i];

         }

         cout << "Please input this edge attaches two vertices subscript and its weight" << endl;

         for(int j=0; j<G.edgeNum; j++)

         {

                   cin >> G.edge[j].from >> G.edge[j].to >> G.edge[j].weight;

         }

         Kruskal(G);

}

int main()

{

         InputInfo();

         system("pause");

         return 0;

}

实验过程中遇到的问题及解决过程

  比如不知道如何存储边集数组,以及比知道如何声明一些变量,函数和怎样去调用Kruskal函数……

解决:通过设置结构体EdgeType与结构体EdgeGraph的联合来存储边集,因为在刚开始我在主函数中用EdgeGraph声明变量G,来作为形参去调用Kruskal(G),编译时就会警告未被初始化的G,的程序出错,后来我将Kruskal(G)在InputInfo()

中调用,因为InputInfo()函数中声明了变量G,并使得G初始化,从而是的程序能正常运行。

测试的图与预期生成的最小树

       

 [实验记录]

实验总结,感想

    通过这次的上机实验,加深了我对课本上的理论知识的认识与理解,然我真实的体验到了从研究问题到解决问题的探索中产生的乐趣,并且体会到问题解决的成就感,虽然在上机调试的时候产生了很多的错误,但经过自己查阅资料,请教同学老师而将问题一一的解决让我体会到学习所带来的乐趣,我希望今后能又更多的理论与实践相结合的课程设计作业,而不是单一的理论的学习。

更多相关推荐:
最小生成树实验报告

北京理工大学软件学院一实验目的1通过上机程序进一步加深对最小生成树的理解2掌握Kruskal算法3学会用程序解决离散数学中的问题4增强我们编写程序的能力二实验内容求带权无向联通平面图的最小生成树三实验环境我的实...

最小生成树实验报告

数据结构课程设计报告题目最小生成树问题院系计算机工程学院学生姓名班级学号起迄日期指导教师20xx20xx年度第2学期一需求分析1问题描述在n个城市之间建设网络只需保证连通即可求最经济的架设方法存储结构采用多种求...

最小生成树数据结构实验报告

摘要最小生成树是数据结构中图的一种重要应用在图中对于n个顶点的连通网可以建立许多不同的生成树最小生成树就是在所有生成树中总的权值最小的生成树本课程设计是以邻接矩阵作为图的存储结构分别采用Prim和Kruskal...

最小生成树实验报告

xie数据结构与算法实验院别年级专业姓名学号计算机科学与信息工程学院20xx级空间信息与数字技术杨哲庆1420xx213820xx年12月实验8最小生成树实验81最小生成树811实验的主要内容和目的使用Prim...

实验九 最小生成树实验报告

一实验目的1使学生熟悉最小生成树的意义和相应算法2掌握带权图的存储结构二实验环境1硬件每个学生需配备计算机一台2软件windows操作系统TurboC三实验要求1能够独立完成带权图的存储和最小生成树的生成四代码...

数据结构实验报告十二—最小生成树问题

问题描述若要在n个城市之间建设通信网络只需要架设n1条线路即可如何以最低的经济代价建设这个通信网是一个网的最小生成树问题一需求分析需定义结构体数组根据权值逐一选择边二概要设计抽象数据类型需定义结构体数组存储每条...

最小生成树实验报告

最小生成树算法的设计与实现一实验目的1根据算法设计需要掌握连通网的灵活表示方法2掌握最小生成树算法如PrimKruskal算法3基本掌握贪心算法的一般设计方法4进一步掌握集合的表示与操作算法的应用二预习与参考1...

Prim最小生成树 实验报告含源码

实验报告题目说明POJ2395OutofRay题目大意Beth有m个农场农场之间有些相通有些不通已知Beth每一英里要一盎司的水Beth希望走遍所有的农场但携带最少的水问Beth最多需要带多少水每个农场都可以补...

计算机算法设计与分析 最小生成树 实验报告

学院实验报告纸计算机科学与工程学院院系网络工程专业071班组计算机算法设计与分析课最小生成树问题1实验目的通过简单的实际应用例子了解和掌握最小生成树问题的要点和方法2算法分析设计思想图的存储使用数组表示法即邻接...

数据结构实验报告 最小生成树

实验报告六数学学院08级4班08020xx15余燕川一实验目的通过对图的基本知识的学习掌握图的基本概念构造最小生成树在此基础上上机实践调试程序二实验题目对一个给定的图GVE构造最小生成树三实验分析1假设网GVE...

最小生成树算法实验报告

作业1最小生成树的生成算法11算法应用背景在实际生活中图的最小花费生成树问题有着广泛的应用例如用图的顶点代表城市顶点与顶点之间的边代表城市之间的道路或通信线路用边的权代表道路的长度或通信线路的费用则最小花费生成...

图的基本操作与kruskal最小生成树实验报告

数据结构1实验五图的基本操作一实验目的1使学生可以巩固所学的有关图的基本知识2熟练掌握图的存储结构3熟练掌握图的两种遍历算法二实验内容问题描述对给定图实现图的深度优先遍历和广度优先遍历基本要求以邻接表为存储结构...

最小生成树实验报告(27篇)