迪杰斯特拉算法(解决单源最短路径问题)

        迪杰斯特拉算法用于解决图的单源最短路径问题,即给定a和b点,求a到b的最短路径。但是局限性在于不能处理图中含有负权边的情况。迪杰斯特拉算法和弗洛伊德算法非常类似,只不过是弗洛伊德是对所有结点对都做了松弛操作,而迪杰斯特拉算法只对给定的结点对做松弛,基本思路是很像的。这里就不解释松弛操作了,详见:弗洛伊德算法

基本思路:

        从给定的起点出发,找一个离它最近且没有访问的点,然后以找到的点为中转点做松弛操作。然后重复上述过程,最后得到起点到其他每个点的最短路径。之所以要选择最近的没有访问过的点是为了可以保存最短路径,其实只要和弗洛伊德一样,顺次遍历其他点就可以得到最短路径的路径和。

数据结构:

  • 图的邻接矩阵,用来保存图的信息
  • visit数组,用来判断一个点有没有被访问过
  • dst数组,用来储存起点到每个点的最短路径,在算法过程中是在动态更新的

算法过程:

  1. 从起点出发,找最近的一个没有访问过的点,即权值最小的边。
  2. 以找到的点为中转点,对没有访问过的点做进行一轮松弛操作。
  3. 重复1,直到所有点都遍历完。

例题:

        给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s,终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。输入n和m,再输入m个四元组,表示两个顶点间的距离和花费,再输入起点和终点。 

        由于这个题里的边还有花费这一属性,所以本题用结构体来保存边的长度和花费。还要一个spend数组,来储存起点到每个点的最短路径的花费。用上述迪杰斯特拉算法的思路来解。

c++代码:

#include
#include
#define inf 999999
#define max 105
using namespace std;
//由于一条边有两个信息,则用结构体来储存 
struct Edge
{
	int len;
	int cost;
};
Edge edge[max][max];
//dst表示起点到每个点的最短距离,spend表示起点到每个点的最短路径下的花费,visit为标记数组 
int m,n,dst[max],visit[max],spend[max];
int main()
{
	int i,j,start,end;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			edge[i][j].cost=0;
			edge[i][j].len=inf;
		}
		edge[i][i].len=0;
	}
	while(m--)
	{
		cin>>i>>j;
		cin>>edge[i][j].len>>edge[i][j].cost;
		edge[j][i].cost=edge[i][j].cost;
		edge[j][i].len=edge[i][j].len;
	}
	cin>>start>>end;
	//对dst和spend初始化为从起点直接到另一个点的距离和花费 
	for(int i=1;i<=n;i++)
	{
		dst[i]=edge[start][i].len;
		spend[i]=edge[start][i].cost;
	}
	memset(visit,0,sizeof(visit));
	visit[start]=1;
	int k;
	for(k=1;kdst[i])
			{
				minlen=dst[i];
				minnode=i;
			}
		}
		//确定要走这个点了,标记为1 
		visit[minnode]=1;
		//对每个点进行松弛操作,因为本题中还要考虑花费,所以当两个路径距离相同时,比较一下花费 
		for(int i=1;i<=n;i++)
		{
			if(visit[i]==0 && dst[i]>(dst[minnode]+edge[minnode][i].len) || dst[i]==(dst[minnode]+edge[minnode][i].len) && spend[i]

 

你可能感兴趣的:(最短路径问题)