假设要在n个城市之间建立通讯联络网,不同城市间建立通讯设施的代价不同,如何在最节省经费的前提下建造这个通讯网。
即找权值之和最小的极小连通子网,问题转换为在连通网中找一颗生成树,最小生成树。
输入:创建图。
输出:组成最小生成树的所有边。
运行结果:
Prim算法:设U代表已并入最小生成树的顶点的集合,最初任选一点放入U,之后找到U到其补集最小边。将对应新顶点并入。共N-1轮即可。
1、从顶点u0开始,令U={u0},初始化u0到其余各顶点距离。
2、{找最小的边输出,并入新结点,赋0+更新表使U到非U距离更小}。
如此重复n-1次。
算法实现:
邻接矩阵存储:
构造表对应的数组,每个元素对应一个顶点,元素取值是U中到当前点最近的点和边的权值,顶点被并入U后权值置0。
typedef double VRType;
struct{ //对应数组 每个元素一个顶点
VertexType adjvex; //U中到当前点最近的点名称
VRType lowcost; //U中点到当前点的最小代价
}closedge[MVNUM];
用Prim算法从v出发求网G最小生成树 输出各边.
void MiniSpanTree_Prim(MGraph G,VertexType v){
//用Prim算法从v出发求网G最小生成树 输出各边
int k=LocateVex(G,v),i,j;
closedge[k].lowcost=0; //将v并入U 赋0
for(j=0;j<G.vexnum;j++){ //据v更新数组元素代价
if(j!=k) {
closedge[j].adjvex=v;
closedge[j].lowcost=G.arcs[k][j].adj;
}
}
for(i=1;i<G.vexnum;i++){//共n-1轮 每轮找最小边输出 赋0更新
k=minimum(G);
printf("%c->%c\n",closedge[k].adjvex,G.vexs[k]); //输出v->k
closedge[k].lowcost=0; //将k号结点并入U 赋0
for(j=0;j<G.vexnum;j++)//据k号结点更新数组元素代价
if(G.arcs[k][j].adj<closedge[j].lowcost){
closedge[j].adjvex=G.vexs[k];
closedge[j].lowcost=G.arcs[k][j].adj;
}
}
}
代价非零的元素中找最小元素 返下标.
int minimum(MGraph G){
//代价非零的元素中找最小元素 返下标
int i,k,flag=0;
double min;
for(i=0;i<G.vexnum;i++){
if(closedge[i].lowcost){
if(!flag){ //初始化最小值
min=closedge[i].lowcost;
k=i; //保存下标
flag=1; //是否初始化标记
}
if(min>closedge[i].lowcost){
min=closedge[i].lowcost;
k=i;
}
}
}
return k;
}
邻接表存储:
void MiniSpanTree_Prim(ALGraph G,VertexType v){
//用Prim算法从v出发求网G最小生成树 输出各边
int k=LocateVex(G,v),i,j;
closedge[k].lowcost=0; //将v并入U 赋0
for(j=0;j<G.vexnum;j++){
if(j!=k) {
closedge[j].adjvex=v;
closedge[j].lowcost=INFINITY;
}
}
ArcNode *p=G.vertices[k].firstarc;
while(p){
closedge[p->adjvex].lowcost=p->adj;
p=p->nextarc;
}
for(i=1;i<G.vexnum;i++){ //共n-1轮 每轮找最小边输出 赋0更新
k=minimum(G);
printf("%c->%c\n",closedge[k].adjvex,G.vertices[k].data); //输出v->k
closedge[k].lowcost=0; //将k号结点并入U 赋0
ArcNode *p=G.vertices[k].firstarc;//据k号结点更新数组元素代价
while(p){
if(p->adj<closedge[p->adjvex].lowcost){
closedge[p->adjvex].adjvex=G.vertices[k].data;
closedge[p->adjvex].lowcost=p->adj;
}
p=p->nextarc;
}
}
}