有向网_最短路径_Dijkstra算法_Flody算法

目录

1.求有向网的最短路径_Dijkstra算法_单源点最短路径问题

1.1建立有向网的邻接矩阵存储结构:

1.2Dijkstra算法

2.Flody算法:求有向网没对顶点之间的最短路径


1.求有向网的最短路径_Dijkstra算法_单源点最短路径问题

Dijkstra算法的关键思想:按路径长度递增的次序产生最短路径 :下面的代码使用Final[]数组来体现按路径长度递增的顺序产生各条最短路径:

有向网G:表示为DN:Directed Network

G的顶点集合V,源点v0

从v0可达到的顶点(即终点)集合S,其他不可达(或在算法运算过程中暂时不可达)的顶点集合V-S

/*
    使用Dijkstra算法,
    求有向网DN的v0顶点到其余顶点v
    的最短路径P[v]以其带权路径长度D[v]
    v0是源点,求源点到图中其他顶点的最短路径

    DN的顶点集合V分为两个集合S  和  V-S
    从源点v0可到达的顶点集合S
    初始S={v0}
    S为已经找到的从源点v0出发的最短路径的终点集合


    P[v][w]为true表明:w是从v0到v当前求得最短路径上的顶点
    v0->v直达的就是起点v0和终点v

    Final[v]为true,当且仅当v属于S集合,表面当前已经求得的从v0到v的最短路径,
    中间过程不一定是最短,但至少表面v0到v可达

    */

1.1建立有向网的邻接矩阵存储结构:

#define INFINITY INT_MAX

typedef struct vexNode{
	int No;
}vexNode;

class DN{
private:
	//采用数组表示法,构造有向网
	int vexnum, arcnum;
	vector<vexNode*> vexNodePtrVec;
	vector<vector<int>> MG;
	/*路径矩阵P:PathMatrix
	P[v][w]为true则代表,则w是从源点v0到v的当前求得的最短路径上的顶点*/
	vector<vector<bool>> P;
	//final[v]为true代表,当且仅当v属于S,即已经求得从v0到v的最短路径终点
	vector<bool> Final;		
	/*最短路径记录列表D,
	记录源点v0到其他各个顶点的最短路径,D[v0]=0;
	若v0可达顶点i,则D[i]为v0->Vi的最短路径值;
	若v0不可达vi,则D[i]=INFINITE
	*/
	vector<int> D;


	/*
	法二:Flody算法:
	*/
	vector<vector<vector<bool> > > PathMatrix;
	vector<vector<int>> DistanceMatrix;

public:
    	DN(){
		CreateDN();
	}
	~DN(){}
	void CreateDN();
    void ShortPath_DIJ(int v0);
	void PrintResultDijkstra();
	/*
	法二:Flody算法:
	*/
	void ShortestPath_FLOYD();
	void PrintDistanceMatrixFLOYD();

}

    void DN::CreateDN()函数构造有向网:

void CreateDN()
	{
		cin >> vexnum >> arcnum;
		for (int i = 0; i < vexnum; i++)
		{
			vexNode* vexNodePtr = new vexNode;
			vexNodePtr->No = i;
			vexNodePtrVec.push_back(vexNodePtr);
			vector<int> rowVec1;
			vector<bool> rowVec2;
			for (int j = 0; j < vexnum; j++)
			{
				rowVec1.push_back(INFINITY);
				rowVec2.push_back(false);
			}
			MG.push_back(rowVec1);
			P.push_back(rowVec2);
			Final.push_back(false);
			D.push_back(INFINITY);

			vector<vector<bool>> PathMatrixDepth;
			vector<int> DistanceMatrixRow;
			for (int j = 0; j < vexnum; j++)
			{
				vector<bool> PathMatrixRow;
				for (int k = 0; k < vexnum; k++)
				{
					PathMatrixRow.push_back(false);
				}
				PathMatrixDepth.push_back(PathMatrixRow);
				DistanceMatrixRow.push_back(INFINITY);
			}

			PathMatrix.push_back(PathMatrixDepth);
			DistanceMatrix.push_back(DistanceMatrixRow);


		}
		int v1, v2, weight;
		for (int i = 0; i < arcnum; i++)
		{
			cin >> v1 >> v2 >> weight;
			MG[v1][v2] = weight;
		}
	}

1.2Dijkstra算法

求有向网的单源节点到其他各个顶点的最短路径:

	void ShortPath_DIJ(int v0)
	{//
	/*

	使用Dijkstra算法,
	求有向网DN的v0顶点到其余顶点v
	的最短路径P[v]以其带权路径长度D[v]
	v0是源点,求源点到图中其他顶点的最短路径

	DN的顶点集合V分为两个集合S  和  V-S
	从源点v0可到达的顶点集合S
	初始S={v0}
	S为已经找到的从源点v0出发的最短路径的终点集合


	P[v][w]为true表明:w是从v0到v当前求得最短路径上的顶点
	v0->v直达的就是起点v0和终点v

	Final[v]为true,当且仅当v属于S集合,表面当前已经求得的从v0到v的最短路径,
	中间过程不一定是最短,但至少表面v0到v可达

	*/

		for (int v = 0; v < vexnum; v++)
		{
			D[v] = MG[v0][v];//D[]的初始化,就是邻接表MG[v0][]上的的权值
			if (D[v] < INFINITY)
			{//D[v] < INFINITY说明v0可直达v,
				P[v][v0] = true;//路径起点的初始化:v0是从v0到v当前求得的最短路径上的顶点(起点初始化)
				P[v][v] = true;//终点初始化,v是从v0到v当前求得的最短路径上的顶点(终点初始化)
			}
		}
		D[v0] = 0;			//v0到v0的距离为0
		Final[v0] = true;	//集合S初始化,v0属于集合S
		//开始主循环,每次求得v0到某个顶点v的最短路径,并将v加入集合S
		for (int i = 0; i < vexnum; i++)
		{
			if (i == v0)
			{//除去v0的,其余的vexnum-1个顶点都遍历一遍
				continue;
			}
			else
			{
				int v = i;
				int min = INFINITY;//当前v0->v的最近距离
				for (int w = 0; w < vexnum; w++)
				{
					if (!Final[w])//w在集合V-S中
					{
						if (D[w] < min)
						{//在D向量中的属于V-S的集合中选择最小的分量
							v = w;
							min = D[w];
						}
					}
				}
				//这里的v是属于V-S集合的
				Final[v] = true;//将v加入到S集合
				//更新当前最短路径和距离
				for (int w = 0; w < vexnum; w++)
				{
					if (MG[v][w] == INFINITY)
					{//从v到w并没有路径
						continue;
					}
					else if (!Final[w] && (min + MG[v][w] < D[w]))
					{//w在集合V-S中,如果min + MG[v][w] < D[w],将更新D[w]
						D[w] = min + MG[v][w];
						P[w] = P[v];
						P[w][w] = true;//更新终点:w是从v0到w当前求得最短路径上的终点
					}
				}
			}
		}
	}

2.Flody算法:求有向网没对顶点之间的最短路径

	/*
	法二:Flody算法:
	*/
	void ShortestPath_FLOYD()
	{
		/*
		Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]
		及其带权长度D[v][w]。
		若P[v][w][u]=true则表明:u是从v到w之间当前求得的最短路径上的顶点
		*/
		for (int v = 0; v < vexnum; v++)
		{
			for (int w = 0; w < vexnum; w++)
			{
				DistanceMatrix[v][w] = MG[v][w];
				if (DistanceMatrix[v][w] < INFINITY)
				{//从v到w有直达路径
					PathMatrix[v][w][v] = true;//从v->w的起点v路径标记初始化
					PathMatrix[v][w][w] = true;//从v->w的终点w路径标记初始化
				}
			}
			DistanceMatrix[v][v] = 0;
		}

		for (int u = 0; u < vexnum; u++)
		{
			for (int v = 0; v < vexnum; v++)
			{
				for (int w = 0; w < vexnum; w++)
				{
					if ((DistanceMatrix[v][u] != INFINITY) && (DistanceMatrix[u][w] != INFINITY) && (DistanceMatrix[v][u] + DistanceMatrix[u][w] < DistanceMatrix[v][w]))
					{//从v->u->w路径比v->w路径更短
						DistanceMatrix[v][w] = DistanceMatrix[v][u] + DistanceMatrix[u][w];
						for (int i = 0; i < vexnum; i++)
						{
							PathMatrix[v][w][i] = PathMatrix[v][u][i] || PathMatrix[u][w][i];
						}
					}
				}
			}
		}
	}

完整代码和测试用例:

// Dijkstra.cpp : 定义控制台应用程序的入口点。
// Flody算法

#include "stdafx.h"
#include<iostream>
#include<vector>
#include<limits>
using namespace std;

#define INFINITY INT_MAX

typedef struct vexNode{
	int No;
}vexNode;

class DN{
private:
	//采用数组表示法,构造有向网
	int vexnum, arcnum;
	vector<vexNode*> vexNodePtrVec;
	vector<vector<int>> MG;
	/*路径矩阵P:PathMatrix
	P[v][w]为true则代表,则w是从源点v0到v的当前求得的最短路径上的顶点*/
	vector<vector<bool>> P;
	//final[v]为true代表,当且仅当v属于S,即已经求得从v0到v的最短路径终点
	vector<bool> Final;		
	/*最短路径记录列表D,
	记录源点v0到其他各个顶点的最短路径,D[v0]=0;
	若v0可达顶点i,则D[i]为v0->Vi的最短路径值;
	若v0不可达vi,则D[i]=INFINITE
	*/
	vector<int> D;

	/*
	法二:Flody算法:
	*/
	vector<vector<vector<bool> > > PathMatrix;
	vector<vector<int>> DistanceMatrix;

public:
	DN(){
		CreateDN();
	}
	~DN(){}
	void CreateDN()
	{
		cin >> vexnum >> arcnum;
		for (int i = 0; i < vexnum; i++)
		{
			vexNode* vexNodePtr = new vexNode;
			vexNodePtr->No = i;
			vexNodePtrVec.push_back(vexNodePtr);
			vector<int> rowVec1;
			vector<bool> rowVec2;
			for (int j = 0; j < vexnum; j++)
			{
				rowVec1.push_back(INFINITY);
				rowVec2.push_back(false);
			}
			MG.push_back(rowVec1);
			P.push_back(rowVec2);
			Final.push_back(false);
			D.push_back(INFINITY);

			vector<vector<bool>> PathMatrixDepth;
			vector<int> DistanceMatrixRow;
			for (int j = 0; j < vexnum; j++)
			{
				vector<bool> PathMatrixRow;
				for (int k = 0; k < vexnum; k++)
				{
					PathMatrixRow.push_back(false);
				}
				PathMatrixDepth.push_back(PathMatrixRow);
				DistanceMatrixRow.push_back(INFINITY);
			}

			PathMatrix.push_back(PathMatrixDepth);
			DistanceMatrix.push_back(DistanceMatrixRow);
		}
		int v1, v2, weight;
		for (int i = 0; i < arcnum; i++)
		{
			cin >> v1 >> v2 >> weight;
			MG[v1][v2] = weight;
		}
	}

	void ShortPath_DIJ(int v0)
	{//
	/*

	使用Dijkstra算法,
	求有向网DN的v0顶点到其余顶点v
	的最短路径P[v]以其带权路径长度D[v]
	v0是源点,求源点到图中其他顶点的最短路径

	DN的顶点集合V分为两个集合S  和  V-S
	从源点v0可到达的顶点集合S
	初始S={v0}
	S为已经找到的从源点v0出发的最短路径的终点集合


	P[v][w]为true表明:w是从v0到v当前求得最短路径上的顶点
	v0->v直达的就是起点v0和终点v

	Final[v]为true,当且仅当v属于S集合,表面当前已经求得的从v0到v的最短路径,
	中间过程不一定是最短,但至少表面v0到v可达

	*/

		for (int v = 0; v < vexnum; v++)
		{
			D[v] = MG[v0][v];//D[]的初始化,就是邻接表MG[v0][]上的的权值
			if (D[v] < INFINITY)
			{//D[v] < INFINITY说明v0可直达v,
				P[v][v0] = true;//路径起点的初始化:v0是从v0到v当前求得的最短路径上的顶点(起点初始化)
				P[v][v] = true;//终点初始化,v是从v0到v当前求得的最短路径上的顶点(终点初始化)
			}
		}
		D[v0] = 0;			//v0到v0的距离为0
		Final[v0] = true;	//集合S初始化,v0属于集合S
		//开始主循环,每次求得v0到某个顶点v的最短路径,并将v加入集合S
		for (int i = 0; i < vexnum; i++)
		{
			if (i == v0)
			{//除去v0的,其余的vexnum-1个顶点都遍历一遍
				continue;
			}
			else
			{
				int v = i;
				int min = INFINITY;//当前v0->v的最近距离
				for (int w = 0; w < vexnum; w++)
				{
					if (!Final[w])//w在集合V-S中
					{
						if (D[w] < min)
						{//在D向量中的属于V-S的集合中选择最小的分量
							v = w;
							min = D[w];
						}
					}
				}
				//这里的v是属于V-S集合的
				Final[v] = true;//将v加入到S集合
				//更新当前最短路径和距离
				for (int w = 0; w < vexnum; w++)
				{
					if (MG[v][w] == INFINITY)
					{//从v到w并没有路径
						continue;
					}
					else if (!Final[w] && (min + MG[v][w] < D[w]))
					{//w在集合V-S中,如果min + MG[v][w] < D[w],将更新D[w]
						D[w] = min + MG[v][w];
						P[w] = P[v];
						P[w][w] = true;//更新终点:w是从v0到w当前求得最短路径上的终点
					}
				}
			}
		}
	}

	void PrintResultDijkstra()
	{
		std::cout << "P[][]=" << endl;
		for (int i = 0; i < vexnum; i++)
		{
			for (int j = 0; j < vexnum; j++)
			{
				if (P[i][j] == true)
				{
					std::cout << "T" << " ";
				}
				else
				{
					std::cout << "F" << " ";
				}
			}
			std::cout << endl;
		}
		std::cout << "Final[]=" << endl;
		for (int i = 0; i < vexnum; i++)
		{
			if (Final[i] == true)
			{
				std::cout << "T" << " ";
			}
			else
			{
				std::cout << "F" << " ";
			}
		}
		std::cout << endl;
		std::cout << "D[]=" << endl;
		for (int i = 0; i < vexnum; i++)
		{
			std::cout << D[i] << " ";
		}
		std::cout << endl;
	}

	/*
	法二:Flody算法:
	*/
	void ShortestPath_FLOYD()
	{
		/*
		Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]
		及其带权长度D[v][w]。
		若P[v][w][u]=true则表明:u是从v到w之间当前求得的最短路径上的顶点
		*/
		for (int v = 0; v < vexnum; v++)
		{
			for (int w = 0; w < vexnum; w++)
			{
				DistanceMatrix[v][w] = MG[v][w];
				if (DistanceMatrix[v][w] < INFINITY)
				{//从v到w有直达路径
					PathMatrix[v][w][v] = true;//从v->w的起点v路径标记初始化
					PathMatrix[v][w][w] = true;//从v->w的终点w路径标记初始化
				}
			}
			DistanceMatrix[v][v] = 0;
		}

		for (int u = 0; u < vexnum; u++)
		{
			for (int v = 0; v < vexnum; v++)
			{
				for (int w = 0; w < vexnum; w++)
				{
					if ((DistanceMatrix[v][u] != INFINITY) && (DistanceMatrix[u][w] != INFINITY) && (DistanceMatrix[v][u] + DistanceMatrix[u][w] < DistanceMatrix[v][w]))
					{//从v->u->w路径比v->w路径更短
						DistanceMatrix[v][w] = DistanceMatrix[v][u] + DistanceMatrix[u][w];
						for (int i = 0; i < vexnum; i++)
						{
							PathMatrix[v][w][i] = PathMatrix[v][u][i] || PathMatrix[u][w][i];
						}
					}
				}
			}
		}
	}

	void PrintDistanceMatrixFLOYD()
	{
		cout << "FLOYD算法求有向网DN的各对顶点之间的最短路径:" << endl;
		for (int i = 0; i < vexnum; i++)
		{
			for (int j = 0; j < vexnum; j++)
			{
				if (DistanceMatrix[i][j] == INFINITY)
				{
					std::cout << "NW" << " ";//No Way!
				}
				else
				{
					cout << DistanceMatrix[i][j] << " ";
				}
			}
			cout << endl;
		}
	}

};

int _tmain(int argc, _TCHAR* argv[])
{
	//溢出情况:
	//INFINITE=2147483647
	//INFINITE + 1 = -2147483648
	//cout << "INFINITE=" << INFINITY << endl;
	//cout << "INFINITE+1=" << INFINITY + 1 << endl;


	DN dn;
	//dn.ShortPath_DIJ(0);
	//dn.PrintResult();

	dn.ShortestPath_FLOYD();
	dn.PrintDistanceMatrixFLOYD();


	system("pause");
	return 0;
}

/*
6 8
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60


输入输出:
6 8
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60
P[][]=
F F F F F F
F F F F F F
T F T F F F
T F F T T F
T F F F T F
T F F T T T
Final[]=
T F T T T T
D[]=
0 2147483647 10 50 30 60
请按任意键继续. . .



6 8
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60
FLOYD算法求有向网DN的各对顶点之间的最短路径:
0 NW 10 50 30 60
NW 0 5 55 NW 65
NW NW 0 50 NW 60
NW NW NW 0 NW 10
NW NW NW 20 0 30
NW NW NW NW NW 0
请按任意键继续. . .

*/

代码分享链接:链接:https://pan.baidu.com/s/17Ta8hDSY8C6XgBeHFQhIDg 密码:cyo5

数据结构有向网_最短路径_Dijkstra算法_Flody算法

猜你喜欢

转载自blog.csdn.net/m0_37357063/article/details/82259086
今日推荐