图---最小生成树---普里姆算法

来源:互联网 发布:idc服务器托管数据安全 编辑:程序博客网 时间:2024/05/16 17:26

普里姆算法简介:

设集合U为最小生成树的顶点集合,开始时只有一个结点,这个结点是我们任意指定的,就从这个结点开始,以此向该结合中添加其余剩下的结点。

其规则如下:(设集合V包含图中所有的顶点)

1、找最小权值的边:该边的两个顶点分别属于集合U和集合V-U   (此时该边就是最小生成树的边

2、将该边的属于集合V-U的顶点并入集合U,从V-U集合中删除       (第 1  、2 步可以防止生成树形成回路

3、重复步骤1,直至集合U包含了图中的所有顶点

这样最小生成树就形成了,也就是所找到的所有边和所有顶点形成的树。若图有n个顶点,则上面的步骤循环了n-1次,因为n个顶点的无向连通图的最小生成树的边为n-1条


下面举例说明,给定的图,如下:

6个顶点和10条边!

此例为严版教材上的例子,书上给定的开始顶点为1,这里我们给定开始的顶点为6,具体步骤如下:



从顶点6开始



这样最小生成树就顺利找出来了,共用了5步,第一步为我们给定的一个结点。

————————————————————————————————————————————————————————————————————————————

关于对严版介绍的代码具体实现,具体如下:


#define MAX_INT0x7fffffff//最大权值#define MAX_VERTEX_NUM20typedef struct ArcCell//顶点关系{int adj;//顶点关系int weight;//边的权值}AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedef struct //集合V-U中顶点和集合U中顶点的关系,即指示两集合顶点之间最小权值的边{int adjVex;//邻接点int lowCost;}Edge;class CGraph{public:int m_vex[MAX_VERTEX_NUM];//顶点向量AdjMatrixm_arcs;//邻接矩阵int m_vexnum;//顶点个数int m_arcnum;//边或弧的条数public:CGraph();~CGraph();int LocateVex(int vex);//定位bool CreateGraph();//创建图void MiniSpanTree_PRIM(int vex);//求最小生成树,输出边int Minimum(Edge edge[]);void PrintGraph();};

#include "Graph.h"#include<iostream>using namespace std;CGraph::CGraph()//构造函数{}CGraph::~CGraph()//析构函数{}int CGraph::LocateVex(int vex){for(int i = 0 ;i<m_vexnum;i++)if(m_vex[i] == vex)return i;return -1;//查找失败!}bool CGraph::CreateGraph(){int i,j;cout<<"输入顶点个数:";cin>>m_vexnum;cout<<"输入边或弧的条数:";cin>>m_arcnum;cout<<"输入顶点数据:";for(i = 0;i < m_vexnum;i++){cin>>m_vex[i];}cout<<endl;//*********初始化邻接矩阵for(i=0;i<m_vexnum;i++){for(j=0;j<m_vexnum;j++){m_arcs[i][j].adj = 0;//无边或弧相连m_arcs[i][j].weight = MAX_INT;//权值为0}}cout<<"输入边或弧的数据:\n";for(i = 0;i < m_arcnum;i++){int vex1,vex2;int k1,k2;int weight;cin>>vex1>>vex2>>weight;;k1 = LocateVex(vex1);k2 = LocateVex(vex2);if(k1>-1 && k1<m_vexnum && k2>-1 && k2<m_vexnum){m_arcs[k1][k2].adj = m_arcs[k2][k1].adj = 1;//无向图的初始化m_arcs[k1][k2].weight = m_arcs[k2][k1].weight = weight;}else//输入错误{cout<<"输入的顶点数据错误!!!\n";return false;}}return true;//创建成功}void CGraph::PrintGraph(){int i,j;cout<<"顶点序列为:";for(i=0;i<m_vexnum;i++)cout<<m_vex[i]<<"  ";cout<<endl<<endl;cout<<"邻接关系为:\n";for(i=0;i<m_vexnum;i++){for(j=0;j<m_vexnum;j++){cout.width(5);//设置输出宽度cout<<m_arcs[i][j].adj<<"  ";}cout<<endl;}cout<<endl<<endl;cout<<"带权矩阵为:\n";for(i=0;i<m_vexnum;i++){for(j=0;j<m_vexnum;j++){cout.width(5);//设置输出宽度cout<<m_arcs[i][j].weight<<"  ";}cout<<endl;}}void CGraph::MiniSpanTree_PRIM(int vex){Edge edge[MAX_VERTEX_NUM];//定义一个结构体数组,用来实现集合U-Vint i,j,k;k = LocateVex(vex);//定位for(i=0;i<m_vexnum;i++)//初始化辅助数组if(i != k){edge[i].adjVex = vex;edge[i].lowCost = m_arcs[i][k].weight;}edge[k].lowCost = 0;//初始 U = {vex}cout<<"最小生成树为:\n";for(i = 1;i<m_vexnum;i++)//选择剩下的顶点{k = Minimum(edge);//找到最小结点的下标cout<<m_vex[k]<<"  "<<edge[k].adjVex<<endl;//输出最小生成树的边   当然我们可以根据实际需要在这步将边保存起来另作他用edge[k].lowCost = 0;//归并结点for( j = 0;j<m_vexnum;j++)//修改原来权值{if(m_arcs[k][j].weight < edge[j].lowCost ){edge[j].lowCost = m_arcs[k][j].weight;edge[j].adjVex = m_vex[k];}}}}int CGraph::Minimum(Edge edge[])//找最小边{int minWeight;int v;int i;for(i =0;i<m_vexnum;i++)//初始最小权值的结点{if(edge[i].lowCost)//权值不为0{v = i;//得到最小结点的下标minWeight = edge[i].lowCost;break;}}//查找最小结点for(i++;i<m_vexnum;i++){if(edge[i].lowCost !=0 && edge[i].lowCost < minWeight){v = i;minWeight = edge[i].lowCost;}}//forreturn v;//返回最小结点所在下标}int main(){CGraph g;//声明一个图对象g.CreateGraph();//创建一个图g.MiniSpanTree_PRIM(6);//求最小生成树cin.get();return 0;}



创建图时所使用的数据为:

6
10
1 2 3 4 5 6
1 2 6
1 3 1
1 4 5
2 3 5
3 4 5
2 5 3
3 5 6
3 6 4
4 6 2

5 6 6

------对于边的数据:前两个数据代表顶点,最后一个数据代表权值,如 5 6 6表示顶点5和顶点6之间边的权值为6

程序运行时可直接复制上去。其运行结果见下图:



输出的最小生成树为边

---------------------------------------------------------------------------------------------


0 0
原创粉丝点击