最短路径(难)

目录

一、Dijkstra算法

(一)演示

(二)核心代码

(三)完整代码

(四)运行结果

二、Floyd算法

(一)详细介绍 

(二)核心代码

(三)完整代码

(四)运行结果


一、Dijkstra算法

  • Dijkstra算法:可以求带权图中一个顶点到其余各顶点的最短路径(单源最短路径) 
  • 基本算法步骤:
    第一步:初始时,顶点集S只含源点,即S=\left \{ \left. v \right \} \right.,顶点v到自己的距离为0.顶点集U包含除v外其他顶点,源点vU中顶点i的距离为边上权值。
    第二步:从U中选取一个顶点u,它是源点vU中距离最小的一个顶点,然后把顶点u加入S
    第三步:以顶点u作为新考虑的中间点,修改U中那些从顶点uj有边的顶点j的最短路径长度
    U中其他顶点从顶点u没有边到达的顶点不需要调整)。考虑顶点u的时候,从源点v到顶点jj属于U)有如下两条路径,在这两条路径中取更短的路径,求从源点v到顶点j的最短路径长度=min(C_{vj},C_{vu}+W_{uj})    ,其中:
      1.不经过顶点u的路径,路径长度为C_{vj}
      2.从顶点u有一条边到达顶点j的路径,该路径由两段构成,其长度为C_{vu}+W_{uj}
    第四步:重复步骤二和步骤三,直到所有顶点都包含在S中。
  • 算法设计:
    S数组表示集合S中的元素,即对于顶点j,S[j]=1表示它在S中,S[j]=0表示它在U
    dist[j]保存从源点v到顶点j的当前最短路径长度,它的初值为<v,j>边上权值
    path[j]保存从源点vj的最短路径,实际上path[j]保存从源点v到顶点j的当前最短路径中顶点j的前一个顶点编号

(一)演示

 

(二)核心代码

void Dijkstra(MGraph G, int v)
{
	int S[MAXV];//用于记录顶点是否在集合U中
	int dist[MAXV];//用于保存从源点到某顶点的当前最短路径长度
	int path[MAXV];//用于保存从源点到某顶点的最短路径
	for (int i = 0; i < G.n; i++)//初始化
	{
		S[i] = 0;
	}
	S[v] = 1;
	for (int i = 0; i < G.n; i++)
	{
		dist[i] = G.edges[v][i];
	}
	for (int j = 0; j < G.n; j++)//path[]数组初始化
	{
		if (S[j]==0&&G.edges[v][j] != INF && G.edges[v][j] != 0)//当v到i没有边的时候
		{
			path[j] = v;
		}
		else
		{
			path[j] = -1;
		}
	}
	
	int u = 0;
	for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
	{
		int min = INF;
		for (int k = 0; k < G.n; k++)//选取不在S中并且具有最小距离的顶点
		{
			if (S[k] == 0 && dist[k] < min)
			{
				min = dist[k];
				u = k;
			}
		}
		S[u] = 1;
		for (int i = 0; i < G.n; i++)
		{
			if (S[i] == 0)//仅仅调整不属于S中的顶点的最短路径长度,且需要考虑新加入S中的顶点
			{
				if (G.edges[u][i] + dist[u] < dist[i] && G.edges[u][i] != INF)
				{
					dist[i] = G.edges[u][i] + dist[u];
					path[i] = u;
				}
			}
		}
	}
	Disp(G, S, dist, path, v);
}
void Disp(MGraph G, int S[], int dist[], int path[],int v)
{
	for (int i = 0; i < G.n; i++)
	{
		if (S[i] == 1 && i != v)
		{
			cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "最短路径长度为:" << dist[i]<<endl;
		}
		if (S[i] == 1 && i != v)
		{
			int d[MAXV]={0};
			int m = 0;
			d[m] = i;//先存放路径上的终点
			int k = path[i];
			if (path[i] == -1)
			{
				cout << "无路径!" << endl;
			}
			else
			{
				while (k != v)
				{
					m++;
					d[m] = k;
					k = path[k];
				}
				m++;
				d[m] = v;//添加路径上的起点
				cout << d[m];//先输出起点
				for (int j = m-1 ; j >= 0; j--)
				{
					cout << "->" << d[j];
				}
				cout << endl;
			}
			
		}
	}
}

(三)完整代码

//Dijk.h
#pragma once
#include<iostream>
using namespace std;

#define MAXV 100
#define INF 10000
typedef int EdgeType;
typedef char VertexType;
typedef struct
{
	int n, e;
	EdgeType edges[MAXV][MAXV];
	VertexType vexs[MAXV];
}MGraph;
void Creat(MGraph& G,int A[][MAXV],int n);//创建图的邻接矩阵
void Print(MGraph G);//打印
void Dijkstra(MGraph G, int v);//从v出发到各个顶点的最短路径
void Disp(MGraph G, int S[], int dist[], int path[],int v);//输出路径
void Dijkstra2(MGraph G, int v, int w);//从v出发到u的最短路径
void DispPath(MGraph G, int S[], int dist[], int path[], int v,int u);//输出从v到u的最短路径
//Dijks.cpp
#include"Dijk.h"
void Creat(MGraph& G, int A[][MAXV], int n)
{
	G.n = n;
	G.e = 0;
	cout << "请依次输入顶点信息:";
	for (int i = 0; i < n; i++)
	{
		cin >> G.vexs[i];
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			G.edges[i][j] = A[i][j];
			if (A[i][j] != 0 && A[i][j] != INF)
			{
				G.e++;
			}
		}
	}
}

void Print(MGraph G)
{
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << G.edges[i][j] << " ";
		}
		cout << endl;
	}
}

void Dijkstra(MGraph G, int v)
{
	int S[MAXV];//用于记录顶点是否在集合U中
	int dist[MAXV];//用于保存从源点到某顶点的当前最短路径长度
	int path[MAXV];//用于保存从源点到某顶点的最短路径
	for (int i = 0; i < G.n; i++)//初始化
	{
		S[i] = 0;
	}
	S[v] = 1;
	for (int i = 0; i < G.n; i++)
	{
		dist[i] = G.edges[v][i];
	}
	for (int j = 0; j < G.n; j++)//path[]数组初始化
	{
		if (S[j]==0&&G.edges[v][j] != INF && G.edges[v][j] != 0)//当v到i没有边的时候
		{
			path[j] = v;
		}
		else
		{
			path[j] = -1;
		}
	}
	
	int u = 0;
	for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
	{
		int min = INF;
		for (int k = 0; k < G.n; k++)//选取不在S中并且具有最小距离的顶点
		{
			if (S[k] == 0 && dist[k] < min)
			{
				min = dist[k];
				u = k;
			}
		}
		S[u] = 1;
		for (int i = 0; i < G.n; i++)
		{
			if (S[i] == 0)//仅仅调整不属于S中的顶点的最短路径长度,且需要考虑新加入S中的顶点
			{
				if (G.edges[u][i] + dist[u] < dist[i] && G.edges[u][i] != INF)
				{
					dist[i] = G.edges[u][i] + dist[u];
					path[i] = u;
				}
			}
		}
	}
	Disp(G, S, dist, path, v);
}

void Disp(MGraph G, int S[], int dist[], int path[],int v)
{
	for (int i = 0; i < G.n; i++)
	{
		if (S[i] == 1 && i != v)
		{
			cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "最短路径长度为:" << dist[i]<<endl;
		}
		if (S[i] == 1 && i != v)
		{
			int d[MAXV]={0};
			int m = 0;
			d[m] = i;//先存放路径上的终点
			int k = path[i];
			if (path[i] == -1)
			{
				cout << "无路径!" << endl;
			}
			else
			{
				while (k != v)
				{
					m++;
					d[m] = k;
					k = path[k];
				}
				m++;
				d[m] = v;//添加路径上的起点
				cout << d[m];//先输出起点
				for (int j = m-1 ; j >= 0; j--)
				{
					cout << "->" << d[j];
				}
				cout << endl;
			}
			
		}
	}
}
void Dijkstra2(MGraph G, int v, int w)//从v出发到w的最短路径
{
	int S[MAXV];
	int dist[MAXV];
	int path[MAXV];
	for (int i = 0; i < G.n; i++)//初始化S[MAXV]数组
	{
		S[i] = 0;
	}
	S[v] = 1;
	for (int i = 0; i < G.n; i++)//初始化dist[MAXV]数组
	{
		dist[i] = G.edges[v][i];
	}
	for (int i = 0; i < G.n-1; i++)//初始化path[MAXV]数组
	{
		if (G.edges[v][i] != INF && G.edges[v][i] != 0)
		{
			path[i] = v;
		}
		else
		{
			path[i] = -1;
		}
	}

	int k = 0;
	for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
	{
		int min = INF;
		for (int j = 0; j < G.n; j++)//选取不在S中并且具有最小距离的顶点
		{
			if (S[j] == 0 && G.edges[v][j] != 0 && dist[j] < min)
			{
				min = dist[j];
				k = j;
			}
		}
		S[k] = 1;
		if (k == w)//如果新加入集合S的顶点恰好是要找的终点,就退出循环
		{
			break;
		}
		else
		{
			for (int j = 0; j < G.n; j++)
			{
				if (S[j] == 0)//更新不属于U中的顶点的最短路径长度
				{
					if (G.edges[v][j] != 0 && G.edges[k][j] + dist[k] < dist[j])
					{
						dist[j] = G.edges[k][j] + dist[k];
						path[j] = k;
					}
				}
			}
		}
		
	}
	DispPath(G, S, dist, path, v, w);
}
void DispPath(MGraph G, int S[], int dist[], int path[], int v, int w)//输出从v到w的最短路径
{
	if (S[w] == 1 && w != v)
	{
		cout << "从" << G.vexs[v] << "到" << G.vexs[w] << "最短路径长度为:" << dist[w] << endl;
	}
	if (S[w] == 1 && w != v)
	{
		int d[MAXV];
		int m = 0;
		d[m] = w;
		int k = path[w];
		while (k != v)
		{
			m++;
			d[m] = k;
			k = path[k];
		}
		m++;
		d[m] = v;
		cout << "最短路径是:" << d[m];
		for (int j = m - 1; j >= 0; j--)
		{
			cout << "->" << d[j];
		}
	}
}
//Text.cpp
#include"Dijk.h"
int main()
{
	int A[][MAXV] = { {0,4,6,6,INF,INF,INF},{INF,0,1,INF,7,INF,INF},{INF,INF,0,INF,6,4,INF},{INF,INF,2,0,INF,5,INF},{INF,INF,INF,INF,0,INF,6},{INF,INF,INF,INF,1,0,8},{INF,INF,INF,INF,INF,INF,0} };
	MGraph G;
	Creat(G, A, 7);
	cout << "图的邻接矩阵:" << endl;
	Print(G);
	Dijkstra(G, 0);
	cout << endl;
	Dijkstra2(G, 2, 6);
	return 0;
}

(四)运行结果

二、Floyd算法

(一)详细介绍 

 

 

 

(二)核心代码

void Floyd(MGraph G)//Floyd算法
{
	int A[MAXV][MAXV];//保存最短路径长度
	int path[MAXV][MAXV];//保存最短路径
	for (int i = 0; i < G.n; i++)//初始化A[][]数组
	{
		for (int j = 0; j < G.n; j++)
		{
			A[i][j] = G.edges[i][j];
		}
	}
	for (int i = 0; i < G.n; i++)//初始化path[][]数组
	{
		for (int j = 0; j < G.n; j++)
		{
			if (G.edges[i][j] == INF || G.edges[i][j] == 0)//i到j不存在边
			{
				path[i][j] = -1;
			}
			else
			{
				path[i][j] = i;//i到j存在边的时候,下标为j的顶点前驱顶点的编号是i
			}
		}
	}
	for (int k = 0; k < G.n; k++)//依次将下标从0到G.n的顶点作为中转点
	{
		for (int i = 0; i < G.n; i++)
		{
			for (int j = 0; j < G.n; j++)
			{
				if ((A[i][k] + A[k][j]) < A[i][j])//找到更短路径长度
				{
					A[i][j] = A[i][k] + A[k][j];//修改路径长度
					path[i][j] = path[k][j];//修改下标为j的顶点的前驱顶点
 //而path[k][j]存放的是恰好是从下标为k到下标为j顶点的路径中,下标为j的顶点的前驱顶点编号
				}
			}
		}
	}
	DisPath(G, A, path);
	/*for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << path[i][j] << " ";
		}
		cout << endl;
	}
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << A[i][j] << " ";
		}
		cout << endl;
	}*/
}
void DisPath(MGraph G, int A[][MAXV], int path[][MAXV])
{
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			if (A[i][j] != 0 && A[i][j] != INF && i != j)
			{
				cout << "从" << G.vexs[i] << "到" << G.vexs[j] << "最短路径长度是:" << A[i][j] << endl;
				int d[MAXV];
				int m = 0;
				d[m] = j;//先存终点的下标
				int k = path[i][j];
				while (k != i && k != -1)
				{
					m++;
					d[m] = k;
					k = path[i][k];
				}
				m++;
				d[m] = i;//存起点的下标
				cout << "路径是:" << d[m];
				for (int p = m - 1; p >= 0; p--)
				{
					cout << "->" << d[p];
				}
				cout << endl;
			}
		}
	}
}

(三)完整代码

//Floyd.h
#pragma once
#include<iostream>
using namespace std;

#define MAXV 100
#define INF 10000
typedef int VertexType;
typedef int EdgeType;
typedef struct
{
	int n, e;
	VertexType vexs[MAXV];
	EdgeType edges[MAXV][MAXV];
}MGraph;
void Creat(MGraph &G, int E[][MAXV], int n);//创建邻接矩阵
void Print(MGraph G);//打印图
void Floyd(MGraph G);//Floyd算法
void DisPath(MGraph G, int A[][MAXV], int path[][MAXV]);//打印最短路径
//Floyd.cpp
#include"Floyd.h"
void Creat(MGraph &G, int E[][MAXV], int n)
{
	G.n = n;
	G.e = 0;
	cout << "请依次输入顶点:";
	for (int i = 0; i < G.n; i++)
	{
		cin >> G.vexs[i];
	}
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			G.edges[i][j] = E[i][j];
			if (E[i][j] != 0 && E[i][j] != INF)
			{
				G.e++;
			}
		}
	}
}
void Print(MGraph G)
{
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << G.edges[i][j] << " ";
		}
		cout << endl;
	}
}

void Floyd(MGraph G)//Floyd算法
{
	int A[MAXV][MAXV];//保存最短路径长度
	int path[MAXV][MAXV];//保存最短路径
	for (int i = 0; i < G.n; i++)//初始化A[][]数组
	{
		for (int j = 0; j < G.n; j++)
		{
			A[i][j] = G.edges[i][j];
		}
	}
	for (int i = 0; i < G.n; i++)//初始化path[][]数组
	{
		for (int j = 0; j < G.n; j++)
		{
			if (G.edges[i][j] == INF || G.edges[i][j] == 0)//i到j不存在边
			{
				path[i][j] = -1;
			}
			else
			{
				path[i][j] = i;//i到j存在边的时候,下标为j的顶点前驱顶点的编号是i
			}
		}
	}
	for (int k = 0; k < G.n; k++)//依次将下标从0到G.n的顶点作为中转点
	{
		for (int i = 0; i < G.n; i++)
		{
			for (int j = 0; j < G.n; j++)
			{
				if ((A[i][k] + A[k][j]) < A[i][j])//找到更短路径长度
				{
					A[i][j] = A[i][k] + A[k][j];//修改路径长度
					path[i][j] = path[k][j];//修改下标为j的顶点的前驱顶点
 //而path[k][j]存放的是恰好是从下标为k到下标为j顶点的路径中,下标为j的顶点的前驱顶点编号
				}
			}
		}
	}
	DisPath(G, A, path);
	/*for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << path[i][j] << " ";
		}
		cout << endl;
	}
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			cout << A[i][j] << " ";
		}
		cout << endl;
	}*/
}


void DisPath(MGraph G, int A[][MAXV], int path[][MAXV])
{
	for (int i = 0; i < G.n; i++)
	{
		for (int j = 0; j < G.n; j++)
		{
			if (A[i][j] != 0 && A[i][j] != INF && i != j)
			{
				cout << "从" << G.vexs[i] << "到" << G.vexs[j] << "最短路径长度是:" << A[i][j] << endl;
				int d[MAXV];
				int m = 0;
				d[m] = j;//先存终点的下标
				int k = path[i][j];
				while (k != i && k != -1)
				{
					m++;
					d[m] = k;
					k = path[i][k];
				}
				m++;
				d[m] = i;//存起点的下标
				cout << "路径是:" << d[m];
				for (int p = m - 1; p >= 0; p--)
				{
					cout << "->" << d[p];
				}
				cout << endl;
			}
		}
	}
}
//Text.cpp
#include"Floyd.h"
int main()
{
	int M[][MAXV] = { {0,5,INF,7},{INF,0,4,2},{3,3,0,2},{INF,INF,1,0} };
	MGraph G;
	Creat(G, M, 4);
	cout << "图的邻接矩阵:" << endl;
	Print(G);
	cout << endl;
	Floyd(G);
	return 0;
}

(四)运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值