目录
1.求有向网的最短路径_Dijkstra算法_单源点最短路径问题
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算法