4001基于Dijsktra算法的最短路径求解

描述

一张地图包括n个城市,假设城市间有m条路径(有向图),每条路径的长度已知。给定地图的一个起点城市和终点城市,利用Dijsktra算法求出起点到终点之间的最短路径。

输入

多组数据,每组数据有m+3行。第一行为两个整数n和m,分别代表城市个数n和路径条数m。第二行有n个字符,代表每个城市的名字。第三行到第m+2行每行有两个字符a和b和一个整数d,代表从城市a到城市b有一条距离为d的路。最后一行为两个字符,代表待求最短路径的城市起点和终点。当n和m都等于0时,输入结束。

输出

每组数据输出两行。第一行为一个整数,为从起点到终点之间最短路的长度。第二行为一串字符串,代表该路径。每两个字符之间用空格隔开。

输入样例 1 

3 3
A B C
A B 1
B C 1
A C 3
A C
6 8
A B C D E F
A F 100
A E 30
A C 10
B C 5
C D 50
E D 20
E F 60
D F 10
A F
0 0

输出样例 1

2
A B C
60
A E D F
//基于Dijsktra算法的最短路径求解 
#include <iostream>
#define MaxInt 32767 //最长长度(无穷大) 
#define MVNum 100    //最大定点数 
using namespace std;
typedef struct{
	char vexs[MVNum];		//定点集 
	int arcs[MVNum][MVNum]; //边集 
	int vexum,arcnum;		//当前定点数量和边数量 
}AMGraph;
void Create_Graph(AMGraph &G,int m,int n){//创建树,输入图、顶点数、边数 
	int arc;//边 
	G.vexum=m;//最大顶点数量等于m 
	G.arcnum=n;//最大边数量等于n 
	for(int i=1;i<=m;i++) cin>>G.vexs[i-1];//输入顶点符号 
	for(int i=1;i<=m;i++) 
		for(int j=1;j<=m;j++)
			G.arcs[i-1][j-1]=MaxInt; //初始化每一条边 
	for(int i=1;i<=n;i++){
		int begin=0,end=0;//边的起点终点位置初始化 l、r是逻辑地址 
		char bbegin,eend;//边的起点终点字符 
		cin>>bbegin>>eend;
		for(int i=1;i<=m;i++)//查找起点字符所在的位置 
			if(G.vexs[i-1]==bbegin){begin=i;break;}
		for(int i=1;i<=m;i++)//查找终点字符所在的位置 
			if(G.vexs[i-1]==eend){end=i;break;}
		cin>>G.arcs[begin-1][end-1];//输入该边的长度 
	}
}
void Get_Way(AMGraph G,int Path[],int temp){//递归输出最短路径(由于本题使用的是前驱法,所以正常输出只能从后往前,为了从前往后。只能使用栈、递归、逆序输出的方式,我这里使用递归) 
	if(Path[temp-1]==0){//如果读到起点了 起点的D是0 这时候直接输出起点 
		cout<<G.vexs[temp-1];
		return;
	}
	Get_Way(G,Path,Path[temp-1]);//递归寻找D前驱的路径 
	cout<<" "<<G.vexs[temp-1];//输出此刻的结点 
} 
void Dijsktra(AMGraph G,char bbegin,char eend){//进行一次Dijsktra算法不改变图本身,输入图、起点、终点 
	int begin=0,end=0;//边的起点终点位置初始化 l、r是逻辑地址
	for(int i=1;i<=G.vexum;i++)//查找起点字符所在的位置 
		if(G.vexs[i-1]==bbegin){begin=i;break;}
	for(int i=1;i<=G.vexum;i++)//查找终点字符所在的位置 
		if(G.vexs[i-1]==eend){end=i;break;}
	int V[G.vexum];//用于表示每个点的最短路径是否已经确认
	int D[G.vexum];//用于存储每个点到起点的距离
	int Path[G.vexum];//用于存储每个点的前驱(逻辑地址),0表示无前驱 
	V[begin-1]=1;//起点入V集合 
	for(int i=1;i<=G.vexum;i++){
		V[i-1]=0;
		D[i-1]=G.arcs[begin-1][i-1];
		Path[i-1]=begin;//所有点的前驱是起点 这里采用逻辑地址 0表示无前驱
	}
	D[begin-1]=0;//起点到自己的距离为0 
	Path[begin-1]=0;//起点的前驱改为0 这里采用逻辑地址 0表示无前驱
	for(int i=1;i<=G.vexum;i++){//最多进行点数次Dijsktra运算 
		int min=MaxInt;//min表示一轮Dijsktra中G-V集合中距离起点最短的距离 
		int v=0;//一轮Dijsktra中G-V集合中距离起点最小的点的逻辑地址,0不存在 
		for(int j=1;j<=G.vexum;j++)//找出G-V集合中到起点最短的点 
			if(D[j-1]<min&&!V[j-1]){
				min=D[j-1];
				v=j;
			}
		V[v-1]=1;//G-V集合中距离起点最小的点入集合V
		if(v==end){//如果这个点恰好是终点,直接输出,省略后面的Dijsktra运算 
			cout<<D[v-1]<<endl;
			Get_Way(G,Path,end); //递归输出路径 
			cout<<endl; //输出换行符
			break;
		}
		for(int j=1;j<=G.vexum;j++)//对以距离起点最短点为出度的边的入度点进行距离更新 
			if(D[v-1]+G.arcs[v-1][j-1]<D[j-1]){
				D[j-1]=D[v-1]+G.arcs[v-1][j-1];
				Path[j-1]=v;
			}			
	}
}
void Calculate(int m,int n){//m定点数,n边数 
	AMGraph G;
	char begin,end;
	Create_Graph(G,m,n);//创建树 
	cin>>begin>>end;
	Dijsktra(G,begin,end);//求最短路径 
}
int main(){
	int m,n;
	while(cin>>m>>n&&m!=0&&n!=0){//每次处理一组数据 
		Calculate(m,n);
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘下来邦我吧

头发加了一根

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值