@第七章 图(三)
图算法的应用
最小生成树 :普里姆算法「Prim」、克鲁斯卡尔算法「Kruskal」
一、普里姆算法实现最小生成树
---------------------------------------------------------------------------------------------------------------------


图1、图2

图3
---------------------------------------------------------------------------------------------------------------------
//邻接矩阵实现普里姆算法
#include<iostream>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<malloc/malloc.h>
using namespace std;
#define MaxVertexNum 100
typedef int EdgeType;
typedef char VertexType[10];
typedef struct
{
VertexType vertex[MaxVertexNum]; //顶点表
EdgeType edges[MaxVertexNum][MaxVertexNum]; //邻接矩阵,即边表
int n,e; //顶点数和边数
}MGraph;
typedef struct
{
VertexType adjvex;
int lowcost;
}miniside[MaxVertexNum];
int LocateVex(MGraph G,VertexType u)
{
int i;
for(i=0;i<G.n;++i)
if(strcmp(u,G.vertex[i])==0)
return i;
return -1;
}
void CreateMGraphAN(MGraph &G)
{
int i,j,k,w;
VertexType vi,vj;
cout<<"请输入顶点数和边数(输入格式为:顶点数,边数):"<<endl;
cin>>G.n>>G.e;
cout<<"请输入顶点信息(输入格式为:顶点号<CR>):"<<endl;
for(i=0;i<G.n;i++)
cin>>G.vertex[i];
for(i=0;i<G.n;i++)
for(j=0;j<G.n;j++)
G.edges[i][j]=0;
cout<<"请输入"<<G.e<<"条边对应的两个顶点的序号及权值(输入格式为:顶点1,顶点2,权值)";
for(k=0;k<G.e;k++)
{
cout<<"顶点1,顶点2,权值:"<<endl;
cin>>vi>>vj>>w;
i=LocateVex(G,vi);
j=LocateVex(G,vj);
G.edges[i][j]=w;
G.edges[j][i]=w;
}
}//CreateMGraphAN
int minimum(miniside S,MGraph G)
{ //求S的最小值,并返回其在S中的序号
int i=0,j,k,min;
while(!S[i].lowcost) //找第一个值不为0的S[i].lowcost的序号
i++;
min=S[i].lowcost; //min标记第一个不为0的值
k=i;//k表示该值的序号
for(j=i+1;j<G.n;j++) //继续向后找
if(S[j].lowcost>0 && S[j].lowcost < min)//找到更小的新的正值
{
min=S[j].lowcost;//min标记此正值
k=j;//k标记此正值的序号
}
return k; //返回当前最小正值在S中的序号
}
void Prim(MGraph G,VertexType u)
{ //用prim算法从顶点u出发构造网G的最小生成树T,输出T的各边
int i,j,k;
miniside S;
k=LocateVex(G,u); //顶点u的序号
for(j=0;j<G.n;++j) //辅助数组初始化
if(j!=k)
{
strcpy(S[j].adjvex,u);//顶点u拷贝到S[j].adjvex
if(G.edges[k][j]==0)
S[j].lowcost=65535;
else
S[j].lowcost=G.edges[k][j]; //顶点u到该点的权值
}
S[k].lowcost=0; //初始,U={u}.U中的顶点到集合U的权值为0
cout<<"最小代价生成树的各条边为:"<<endl;
for(i=1;i<G.n;++i) //选择其余G.n-1个顶点
{
k=minimum(S,G); //求出最小生成树的下一个结点:第k个结点
cout<<S[k].adjvex<<"->"<<G.vertex[k]<<endl; //输出最小生成树的边
S[k].lowcost=0; //将第k个顶点并入U集
for(j=0;j<G.n;++j)
if(G.edges[k][j] < S[j].lowcost && G.edges[k][j]!=0)
{ //新顶点并入U集后重新选择最小边
strcpy(S[j].adjvex,G.vertex[k]);
S[j].lowcost=G.edges[k][j];
}
}
} //prim
void print(MGraph G)
{
int i,j;
for(i=0;i<G.n;i++)
{
for(j=0;j<G.n;j++)
cout<<setw(4)<<G.edges[i][j];
cout<<endl;
}
}
int main()
{
MGraph G;
CreateMGraphAN(G);
cout<<"输出图的邻接矩阵:"<<endl;
print(G);
Prim(G,G.vertex[0]);
}
输出结果
请输入顶点数和边数(输入格式为:顶点数,边数):
5 8
请输入顶点信息(输入格式为:顶点号<CR>):
v1
v2
v3
v4
v5
请输入8条边对应的两个顶点的序号及权值(输入格式为:顶点1,顶点2,权值)顶点1,顶点2,权值:
v1 v2 4
顶点1,顶点2,权值:
v1 v3 1
顶点1,顶点2,权值:
v1 v4 5
顶点1,顶点2,权值:
v2 v3 4
顶点1,顶点2,权值:
v2 v5 2
顶点1,顶点2,权值:
v3 v4 4
顶点1,顶点2,权值:
v3 v5 3
顶点1,顶点2,权值:
v4 v5 5
输出图的邻接矩阵:
0 4 1 5 0
4 0 4 0 2
1 4 0 4 3
5 0 4 0 5
0 2 3 5 0
最小代价生成树的各条边为:
v1->v3
v3->v5
v5->v2
v3->v4
二、克鲁斯卡尔算法
#include<iostream>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<malloc/malloc.h>
using namespace std;
#define MaxVertexNum 100
typedef int EdgeType;
typedef char VertexType[10];
typedef struct
{
VertexType vertex[MaxVertexNum]; //顶点表
EdgeType edges[MaxVertexNum][MaxVertexNum]; //邻接矩阵,即边表
int vexnum,edgenum; //顶点数和边数
}MGraph;
struct side
{
int a,b;//边的两顶点序号
int weight; //边的权值
};
int LocateVex(MGraph G,VertexType u)
{
int i;
for(i=0;i<G.vexnum;++i)
if(strcmp(u,G.vertex[i])==0)
return i;
return -1;
}
void CreateMGraphAN(MGraph &G)
{
int i,j,k,w;
VertexType vi,vj;
cout<<"请输入顶点数和边数(输入格式为:顶点数,边数):"<<endl;
cin>>G.vexnum>>G.edgenum;
cout<<"请输入顶点信息(输入格式为:顶点号<CR>):"<<endl;
for(i=0;i<G.vexnum;i++)
cin>>G.vertex[i];
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++)
G.edges[i][j]=0;
cout<<"请输入"<<G.edgenum<<"条边对应的两个顶点的序号及权值(输入格式为:顶点1,顶点2,权值)";
for(k=0;k<G.edgenum;k++)
{
cout<<"顶点1,顶点2,权值:"<<endl;
cin>>vi>>vj>>w;
i=LocateVex(G,vi);
j=LocateVex(G,vj);
G.edges[i][j]=w;
G.edges[j][i]=w;
}
}//CreateMGraphAN
void Kruskal(MGraph G)
{
int set[MaxVertexNum],senumber=0,sb,i,j,k;
side se[MaxVertexNum*(MaxVertexNum-1)/2];//存储边信息的一维数组
for(i=0;i<G.vexnum;i++)
for(j=i+1;j<G.vexnum;j++)
if(G.edges[i][j]>0 && G.edges[i][j]<INFINITY)
{
k=senumber-1;
while (k>=0)
if(se[k].weight>G.edges[i][j])
{
se[k+1]=se[k];
k--;
}
else
break;
se[k+1].a=i;
se[k+1].b=j;
se[k+1].weight=G.edges[i][j];
senumber++;
}
cout<<"i se[i].a se[i].b se[i].weight"<<endl;
for(i=0;i<senumber;i++)
cout<<i<<setw(6)<<se[i].a<<setw(9)<<se[i].b<<setw(10)<<se[i].weight<<endl;
for(i=0;i<G.vexnum;i++)
set[i]=i;
cout<<"最小代价生成树的各条边是:"<<endl;
j=0;
k=0;
while(k<G.vexnum-1)
{
if(set[se[j].a]!=set[se[j].b])
{
cout<<G.vertex[se[j].a]<<"-"<<G.vertex[se[j].b]<<endl;
sb=set[se[j].b];
for(i=0;i<G.vexnum;i++)
if(set[i]==sb)
set[i]=set[se[j].a];
k++;
}
j++;
}
}
void print(MGraph G)
{
int i,j;
for(i=0;i<G.vexnum;i++)
{
for(j=0;j<G.vexnum;j++)
cout<<setw(4)<<G.edges[i][j];
cout<<endl;
}
}
int main()
{
MGraph G;
CreateMGraphAN(G);
cout<<"输出图的邻接矩阵:"<<endl;
print(G);
Kruskal(G);
}
---------------------------------------------------------------------------------------------------------------------


图4、图5
---------------------------------------------------------------------------------------------------------------------