求图的最短路径和最小生成树
const int MaxValue=10000;
//定义邻接矩阵类型
typedef int** adjmatrix;
//初始化图的邻接矩阵
void InitGMatrix(adjmatrix& GA, int n);
//建立图的邻接矩阵
void CreateMatrix(adjmatrix GA, int n, int k1, int k2);
//k1为0则无向否则为有向, k2为0则无权否则为有权
//从初始点vi出发深度优先搜索由邻接矩阵GA表示的图
void dfsMatrix(adjmatrix GA, bool*& visited, int i, int n);
//从初始点vi出发广度优先搜索由邻接矩阵GA表示的图
void bfsMatrix(adjmatrix GA, bool*& visited, int i, int n);
//定义邻接表中的边结点类型
struct edgenode {
int adjvex; //邻接点域
int weight; //权值域
edgenode* next; //指向下一个边结点的链域
};
//定义邻接表类型
typedef edgenode** adjlist;
//初始化图的邻接表
void InitGAdjoin(adjlist& GL, int n);
//建立图的邻接表
void CreateAdjoin(adjlist GL, int n, int k1, int k2);
//从初始点vi出发深度优先搜索由邻接表GL表示的图
void dfsAdjoin(adjlist GL, bool*& visited, int i, int n);
//从初始点vi出发广度优先搜索由邻接表GL表示的图
void bfsAdjoin(adjlist GL, bool*& visited, int i, int n);
//根据图的邻接矩阵得到图的邻接表
void graphChange(adjmatrix GA, adjlist GL, int n);
//定义边集数组中的元素类型
struct edge {
int fromvex; //起点域
int endvex; //终点域
int weight; //权域
};
//定义边集数组类型
typedef edge* edgeset;
//输出边集数组中的每条边
void OutputEdgeSet(edgeset GE, int e);
//根据图的邻接矩阵生成图的边集数组
void ChangeEdgeSet(adjmatrix GA, edgeset GE, int n, int e);
#include<iostream.h>
//初始化图的邻接表
void InitGAdjoin(adjlist& GL, int n)
{
GL=new edgenode*[n];
for(int i=0; i<n; i++) GL[i]=NULL;
}
//检查输入的边序号是否越界,若越界则重输
void Check(int n, int& i, int& j);
//初始化图的邻接矩阵
void InitGMatrix(adjmatrix& GA, int n)
{
GA=new int*[n];
int i,j;
for(i=0; i<n; i++)
GA[i]=new int [n];
for(i=0; i<n; i++)
for(j=0; j<n; j++)
if(i==j) GA[i][j]=0;
else GA[i][j]=MaxValue;
}
//建立图的邻接矩阵
void CreateMatrix(adjmatrix GA, int n, int k1, int k2)
//k1为0则无向否则为有向, k2为0则无权否则为有权
{
int i,j,k,e,w;
cout<<"输入图的总边数:";
cin>>e;
if(k1==0 && k2==0) { //建立无向无权图
cout<<"输入"<<e<<"条无向无权边的起点和终点序号!"<<endl;
for(k=1; k<=e; k++) {
cin>>i>>j;
Check(n,i,j);
GA[i][j]=GA[j][i]=1;
}
}
else if(k1==0 && k2!=0) { //建立无向有权图
cout<<"输入"<<e<<"条无向带权边的起点和终点序号及权值!"<<endl;
for(k=1; k<=e; k++) {
cin>>i>>j>>w;
Check(n,i,j);
GA[i][j]=GA[j][i]=w;
}
}
else if(k1!=0 && k2==0) { //建立有向无权图
cout<<"输入"<<e<<"条有向无权边的起点和终点序号!"<<endl;
for(k=1; k<=e; k++) {
cin>>i>>j;
Check(n,i,j);
GA[i][j]=1;
}
}
else if(k1!=0 && k2!=0) { //建立有向有权图
cout<<"输入"<<e<<"条有向有权边的起点和终点序号及权值!"<<endl;
for(k=1; k<=e; k++) {
cin>>i>>j>>w;
Check(n,i,j);
GA[i][j]=w;
}
}
}
//从初始点vi出发深度优先搜索由邻接矩阵GA表示的图
void dfsMatrix(adjmatrix GA, int*& visited, int i, int n)
{
cout<<i<<' ';
visited[i]=1; //标记vi已被访问过
for(int j=0; j<n; j++) //依次搜索vi的每个邻接点
if(i!=j && GA[i][j]!=MaxValue && !visited[j])
dfsMatrix(GA,visited,j,n);
}
//从初始点vi出发广度优先搜索由邻接矩阵GA表示的图
void bfsMatrix(adjmatrix GA, int*& visited, int i, int n)
{
const int MaxLength=30;
//定义一个队列q,其元素类型应为整型
int q[MaxLength]={0};
//定义队首和队尾指针
int front=0, rear=0;
//访问初始点vi
cout<<i<<' ';
//标记初始点vi已访问过
visited[i]=1;
//将已访问过的初始点序号i入队
q[++rear]=i;
//当队列非空时进行循环处理
while(front!=rear) {
//删除队首元素,第一次执行时k的值为i
front=(front+1)%MaxLength;
int k=q[front];
//依次搜索vk的每一个可能的邻接点
for(int j=0; j<n; j++)
{
if(k!=j && GA[k][j]!=MaxValue && !visited[j]) {
cout<<j<<' '; //访问一个未被访问过的邻接点vj
visited[j]=true; //标记vj已访问过
rear=(rear+1)%MaxLength; //顶点序号j入队
q[rear]=j;
}
}
}
}
//检查输入的边序号是否越界,若越界则重输
void Check(int n, int& i, int& j)
{
while(1) {
if(i<0 || i>=n ||j<0 || j>=n)
cout<<"输入有误,请重输!";
else return;
cin>>i>>j;
}
}
//利用普里姆算法从顶点v0出发求出用邻接矩阵GA表示的图的最小生成树,
//最小生成树的边集存于数组CT中
void Prim(adjmatrix GA, edgeset CT, int n)
{
int i,j, k, min, t, m, w;
//给CT赋初值,对应为v0依次到其余各顶点的边
for(i=0; i<n-1; i++) {
CT[i].fromvex=0;
CT[i].endvex=i+1;
CT[i].weight=GA[0][i+1];
}
//进行n-1次循环,每次求出最小生成树中的第k条边
for(k=1; k<n; k++)
{
//从CT[k-1]~CT[n-2]中查找最短边CT[m]
min=MaxValue;
m=k-1;
for(j=k-1; j<n-1; j++)
if(CT[j].weight<min) {
min=CT[j].weight;
m=j;
}
//把最短边对调到第k-1下标位置
edge temp=CT[k-1];
CT[k-1]=CT[m];
CT[m]=temp;
//把新并入最小生成树T中的顶点序号赋给j
j=CT[k-1].endvex;
//修改有关边,使T中到T外的每一个顶点各保持
//一条到目前为止最短的边
for(i=k; i<n-1; i++) {
t=CT[i].endvex;
w=GA[j][t];
if(w<CT[i].weight) {
CT[i].weight=w;
CT[i].fromvex=j;
}
}
}
}
//初始化图的边集数组
void InitGEdge(edgeset& GE, int e)
{
GE=new edge[e];
for(int i=0; i<e; i++) GE[i].weight=0;
}
//输出边集数组中的每条边
void OutputEdgeSet(edgeset GE, int e)
{
cout<<'{';
for(int i=0; i<=e-2; i++) {
cout<<'('<<GE[i].fromvex<<','<<GE[i].endvex<<')';
cout<<GE[i].weight<<", ";
}
if(e>0) {
cout<<'('<<GE[e-1].fromvex<<','<<GE[e-1].endvex<<')';
cout<<GE[e-1].weight<<' ';
}
cout<<'}'<<endl;
}
//求最短路径(狄克斯特拉算法)
void PATH(adjlist path,int m,int j)
//由顶点m的最短距离和顶点j构成到顶点j的目前最短路径
{
edgenode *p,*q,*s;
//把顶点j的当前路径清除掉
p=path[j];
while(p!=NULL){
path[j]=p->next;
delete p;
p=path[j];
}
//把顶点m的最短路径拷贝过来到顶点j的最短路径上
p=path[m];
while(p!=NULL){
q=new edgenode;
q->adjvex=p->adjvex;
if(path[j]==NULL)
path[j]=q;
else
s->next=q;
s=q;
p=p->next;
}
//把顶点j加入到path[j]单链表的最后,形成新的最短路径
q=new edgenode;
q->adjvex=j;
q->next=NULL;
s->next=q;
}
void Dijkstra(adjmatrix GA, int dist[],adjlist path,int i,int n)
//求出图GA中从i点到、其他的每个结点的的最短距离和最短路径,它们分别放在dist和path数组中。
{
int j,k,w,m;
int *s=new int [n];
for(j=0;j<n;j++){
if(j==i)
s[j]=1;
else
s[j]=0;
dist[j]=GA[i][j];
if(dist[j]<MaxValue&&j!=i){
edgenode *p1=new edgenode;
edgenode *p2=new edgenode;
p1->adjvex=i;
p2->adjvex=j;
p2->next=NULL;
p1->next=p2;
path[j]=p1;
}
else
path[j]=NULL;
}
//共进行n-2次循环,每次求出从源点i到终点m的最短路径及长度
for(k=1;k<=n-2;k++)
{
//求出第k个终点m
w=MaxValue;m=i;
for(j=0;j<n;j++)
if(s[j]==0&&dist[j]<w){
w=dist[j];
m=j;
}
//如果条件成立,就把顶点m并入集合s中,否则就退出循环,因为剩下的顶点
//他们的的最短路径长度都是MaxValue,无需再计算下去
if(m!=i)
s[m]=1;
else
break;
//对S元素为0的对应的dist和path中的元素都做必要的修改
for(j=0;j<n;j++)
if(s[j]==0&&dist[m]+GA[m][j]<dist[j]){
dist[j]=dist[m]+GA[m][j];
PATH(path,m,j);
}
}
}
//输出邻接表
void Outadjlist(adjlist GL,int n)
{
for(int k=0;k<n;k++)
{
edgenode *p=GL[k];
while(p!=NULL){
cout<<p->adjvex<<" ";
p=p->next;
}
cout<<endl;
}
}
void Outminload(adjlist GL,int begin,int end)
{
edgenode *p=GL[end];
while(p!=NULL){
cout<<p->adjvex;
if(p->next==NULL) break;
cout<<"--->";
p=p->next;
}
cout<<endl;
}
void main()
{
int n;
int begin,end;
cout<<"输入顶点的个数"<<endl;
cin>>n;
int *visited=new int[n];
for(int k=0;k<n;k++)
visited[k]=0;
adjmatrix GA;
InitGMatrix(GA,n);
CreateMatrix(GA,n,1,1);
cout<<"这个图是"<<endl;
for(int m=0;m<n;m++)
for(int s=0;s<n;s++)
{
cout<<GA[m][s]<<" ";
if(s==n-1) cout<<endl;
}
//cout<<"图的深度遍历:"<<endl;
//dfsMatrix(GA,visited,0,n);
//cout<<endl;
//cout<<"图的广度遍历:"<<endl;
//bfsMatrix(GA,visited,0,n);
//cout<<endl;
//dfsMatrix(GA,visited,1,n);
//edgeset GE;
//InitGEdge(GE,n-1);
//Prim(GA,GE,n);
//cout<<"最小生成树"<<endl;
//OutputEdgeSet(GE,6);//求出最小生成树
while(1){
cout<<"*****************************************"<<endl;
cout<<" 求图的最小距离和最小路径 "<<endl;
cout<<"*****************************************"<<endl;
////////////////////////////////
int *dist=new int[n];
adjlist path;
InitGAdjoin(path,n);
cout<<"请输入任意两点,求最短路径"<<endl;
cin>>begin>>end;
Dijkstra(GA,dist,path,begin,n);
cout<<"最小距离是"<<endl;
cout<<dist[end]<<endl;
cout<<"最小路径是"<<endl;
Outminload(path,begin,end);
}
}
浙公网安备 33010602011771号