我们先来分析一下这个问题。某个地区n个城市构成一个交通图,我们可以使用图结构来描述这个问题,其对应关系如下:
这样,求解各个城市之间的最短总距离问题就归结为该图的最小生成树问题。
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。如图:
假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。
此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。
#include
#include
#include
#define MaxNum 20 //图的最大顶点数
#define MaxValue 65535 //最大值
#define USED 0; //已选用顶点
#define NoL -1 //非邻接顶点
typedef struct
{
char Vertex[MaxNum]; //保存顶点信息(序号或字母)
int GType; //图的类型(0:无向图,1)
int VertexNum; //顶点的数量
int EdgeNum; //边的数量
int EdgeWeight[MaxNum][MaxNum]; //保存边的权
int isTrav[MaxNum]; //定义邻接矩阵图结构
}GraphMatrix;
void CreateGraph(GraphMatrix *GM)
{
int i,j,k;
int weight;
char EstartV,EendV;
std::cout<<"输入图中各顶点信息\n";
for (i = 0; iVertexNum; i++)
{
getchar();
printf("第%d个顶点:",i+1);
scanf("%c",&(GM->Vertex[i]));
}
std::cout<<"输入构成各边的顶点及权值:\n";
for (k = 0; k EdgeNum; k++)
{
getchar();
printf("第%d条边:",k+1);
scanf("%c %c %d",&EstartV,&EendV,&weight);
for ( i= 0; EstartV != GM->Vertex[i]; i++);
for ( j= 0; EendV != GM->Vertex[j]; j++);
GM->EdgeWeight[i][j] = weight;
if (GM->GType == 0) //若是无向图
{
GM->EdgeWeight[j][i] = weight;
}
}
}
void ClearGraph(GraphMatrix *GM)
{
int i,j;
for (i=0; iVertexNum; i++)
{
for (j=0; jVertexNum; j++)
{
GM->EdgeWeight[i][j] = MaxValue;
}
}
}
void OutGraph(GraphMatrix *GM)
{
int i,j;
for (j=0; jVertexNum; j++)
{
printf("\t%c",GM->Vertex[j]);
}
std::cout<<"\n";
for (i=0; iVertexNum; i++)
{
printf("%c",GM->Vertex[i]);
for (j=0; jVertexNum; j++)
{
if (GM->EdgeWeight[i][j] == MaxValue)
{
printf("\tZ"); //以Z表示无穷大
}
else
{
printf("\t%d",GM->EdgeWeight[i][j]); //输出边的权值
}
}
std::cout<<"\n";
}
}
void PrimGraph(GraphMatrix GM) //最小生成树算法
{
int i,j,k,min,sum;
int weight[MaxNum]; //权值
char vtempx[MaxNum]; //临时顶点信息
sum = 0;
for(i = 1; i0) //到具有更小权值的未使用边
{
min = weight[j]; //保存权植
k = j; //保存邻接点序号
}
}
sum +=min; //权值累加
printf("(%c,%c),",vtempx[k],GM.Vertex[k]); //输出生成树一条边
vtempx[k] = USED;
weight[k] = MaxValue;
for (j = 0; j
演示效果图:
求解城市之间的最短距离是一个非常实际的问题。其大意如下:
某个地区有n个城市,如何选择路线使某个城市到某个指定城市的距离最短?
注:这里需要求解的最短路径指两个城市之间的最短距离,面不是所有城市之间最短总距离。
算法步骤如下:
1. 初始时令 S={V0},T={其余顶点},T中顶点对应的距离值
若存在
若不存在
2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S
3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
#include
#include
#include
#define MaxNum 20 //图的最大顶点数
#define MaxValue 65535 //最大值
int path[MaxNum]; //两点经过的顶点集合的数组
int tmpvertex[MaxNum]; //最短路径的起始点集合
#define USED 0; //已选用顶点
#define NoL -1 //非邻接顶点
typedef struct
{
char Vertex[MaxNum]; //保存顶点信息(序号或字母)
int GType; //图的类型(0:无向图,1)
int VertexNum; //顶点的数量
int EdgeNum; //边的数量
int EdgeWeight[MaxNum][MaxNum]; //保存边的权
int isTrav[MaxNum]; //定义邻接矩阵图结构
}GraphMatrix;
void CreateGraph(GraphMatrix *GM)
{
int i,j,k;
int weight;
char EstartV,EendV;
std::cout<<"输入图中各顶点信息\n";
for (i = 0; iVertexNum; i++)
{
getchar();
printf("第%d个顶点:",i+1);
scanf("%c",&(GM->Vertex[i]));
}
std::cout<<"输入构成各边的顶点及权值:\n";
for (k = 0; k EdgeNum; k++)
{
getchar();
printf("第%d条边:",k+1);
scanf("%c %c %d",&EstartV,&EendV,&weight);
for ( i= 0; EstartV != GM->Vertex[i]; i++);
for ( j= 0; EendV != GM->Vertex[j]; j++);
GM->EdgeWeight[i][j] = weight;
if (GM->GType == 0) //若是无向图
{
GM->EdgeWeight[j][i] = weight;
}
}
}
void ClearGraph(GraphMatrix *GM)
{
int i,j;
for (i=0; iVertexNum; i++)
{
for (j=0; jVertexNum; j++)
{
GM->EdgeWeight[i][j] = MaxValue;
}
}
}
void OutGraph(GraphMatrix *GM)
{
int i,j;
for (j=0; jVertexNum; j++)
{
printf("\t%c",GM->Vertex[j]);
}
std::cout<<"\n";
for (i=0; iVertexNum; i++)
{
printf("%c",GM->Vertex[i]);
for (j=0; jVertexNum; j++)
{
if (GM->EdgeWeight[i][j] == MaxValue)
{
printf("\tZ"); //以Z表示无穷大
}
else
{
printf("\t%d",GM->EdgeWeight[i][j]); //输出边的权值
}
}
std::cout<<"\n";
}
}
void DisMin(GraphMatrix GM,int vend) //最短路径算法
{
int weight[MaxNum]; //某终止点到各顶点的最短路径长度
int i,j,k,min;
vend--;
for (i =0; i0) //有效权值
{
path[i] = vend; //保存边
}
}
for (i=0; i
演示结果:
演示效果图:
参考书籍:《C/C++常用算法手册》