问题引入:
假设我们要设计一个电子电路,我们常常需要将多个组件的针脚连接在一起。要连接n个针脚,可以用n-1根连线,每跟连线,连接两个针脚。很显然,我们希望所用连线的长度最短。
可以把上述的连线问题用一个连通的无向图来表示
G=(V,E)
,V是针脚即点的集合,E是针脚之间可能的连接(边的集合),并且对于每条边
(u,v)∈E
,我们赋予它权重
w(u,v)
作为连接针脚u和针脚v的代价(连线的长度),我们希望找到一个无环的子集
T⊆E
,能够将所有节点(针脚)连接起来,又具备最小的权重,即
w(T)=∑(u,v)∈Tw(u,v)
的值最小。因为图是无环的,又连通了所有的顶点,所以T必然是一棵树,这样的树我们就成为最小生成树。
Prim算法是解决最小生成树的一种方法,属于贪心算法。具体思想是,从1个根节点R出发( R∈A ),一直长大到覆盖V中所有的顶点为止,算法每一步在连接集合A和A之外的所有边中,选择一条轻量级边加入到A中,算法终止时,A中的边形成一个最小生成树。
下面给出我个人的一个实现代码:
#include <iostream>
#define INIFY 65533
#define ROW 9
#define COL 9
class Prim{
private:
int Array[ROW][COL];
public:
void CreateGraphy(){
int i,j,k,EdgeNumbers;
std::cout<<"输入边的数量: "<<std::endl;
std::cin>>EdgeNumbers;
//初始化
for(int i=0;i<ROW;i++)
for(int j=0;j<COL;j++)
Array[i][j]=INIFY;
//建立邻接关系
std::cout<<"请输入顶点的邻接关系及权重: "<<std::endl;
while(EdgeNumbers--){
std::cin>>i>>j>>k;
//无向图
Array[i][j]=k;
Array[j][i]=k;
}
}
void PrimAlgorithm(){
int VertexNumber=ROW;
int i,j,k,Min;
int lowcost[VertexNumber],Adj[VertexNumber];
//初始化根节点
lowcost[0]=0,Adj[0]=0;
std::cout<<"最小生成树的边为: "<<std::endl;
for(int i=1;i<VertexNumber;i++){
lowcost[i]=Array[0][i];
Adj[i]=0;
}
for (i = 1; i <VertexNumber; i++){
Min =INIFY; /* 初始化最小权值为∞, */
j = 1;
k = 0;
//在当前状况下 找到最小权重值
while(j<VertexNumber){
if (lowcost[j] != 0 && lowcost[j] < Min){
Min = lowcost[j];
k = j;
}
j++;
}
std::cout << "(" <<Adj[k] << ", " << k << ")" << " "; /*打印当前边中权重最小的边,贪心的体现*/
lowcost[k] = 0;/* 置为0 说明已经处理过*/
for(j=1; j<VertexNumber; j++){
if (lowcost[j] != 0 && Array[k][j]<lowcost[j]){
lowcost[j]=Array[k][j];/* 将较小的权值存入lowcost相应位置 */
Adj[j]=k;/* 将下标为k的顶点存入Adj */
}
}
}
std::cout<<std::endl;
}
};
int main(void){
Prim ivec;
ivec.CreateGraphy();
ivec.PrimAlgorithm();
return 0;
}
测试用例为算法导论中讲prim算法时的测试用例。
其中a b c d e f g h i 我用 1 2 3 4 5 6 7 8代替。
运行结果:
————————————————————————————————————
参考资料:算法导论第三版
http://blog.csdn.net/jnu_simba/article/details/8869876