狄杰斯特拉算法
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 10000;//最大顶点数
const int inf = 1000000000;//无穷大 10的九次方
struct node
{
int layer;
int id;//结点编号和层号
};
vector<node>adj[maxn];//邻接表的bfs遍历
//用户输入顶点个数 边数 起点编号 单源最短路径问题 给定图G(V,E)和起点s,求出起点s到其他顶点的最短距离
int G[maxn][maxn], n,u,bian,beginn;//n:顶点数(自己设置 bian:边数 beginn:起点)图一般是全局变量
int d[maxn];//起点到各顶点的最短路径长度
bool inq[maxn] = {
false };
//邻接矩阵法 该算法只能应对所有边权都是非负数的情况
void dijksra(int begin)//begin为起点
{
fill(d, d + maxn, inf);
d[begin] = 0;//到自身的距离为0
for (int i = 0; i < n; i++)//循环n次
{
int min = inf;
u = -1;//u使得d[u]最小 min存放最小的d[u]
for (int j = 0; j < n; j++) {
//找到未访问的顶点中d[]最小的
if (inq[j] == false && d[j] < min)
{
u = j;
min = d[j];
}
}
if (u == -1) return;//如果u未发生变化则找不到小于inf的d[u],说明剩下的顶点和begin不连通
inq[u] = true;//标记为已经访问过
for (int j = 0;j < n;j++)//如果j未访问&&u可以到达j&&以u为中介点可以使得d[j]更优
{
if (inq[j] == false && G[u][j]!=inf && G[u][j] + d[u] < d[j])
d[j] = G[u][j] + d[u];
}
}
}
int main()
{
int u, v, j;
cin >> n >> bian >> beginn;//输入顶点个数 边数 起点编号(点的编号从0开始
fill(G[0], G[0] + maxn * maxn, inf);//初始化图G一开始全都是无穷大
for (int i = 0; i < bian; i++)
{
cin >> u >> v >> j;//输入点u v以及从u到v的边权
G[u][v] = j;
}
dijksra(beginn);
for (int i = 0; i < n; i++)
cout << d[i] << " ";//输出所有顶点的最短距离
}
`
如果有多条最短路径:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201126154230862.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzU4NTc0,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201126154336852.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzU4NTc0,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020112615424832.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzU4NTc0,size_16,color_FFFFFF,t_70#pic_center)
## 通过vector类型的数组pre寻找最短路径
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201128150421976.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMzU4NTc0,size_16,color_FFFFFF,t_70#pic_center)
```cpp
int st;
int optvalue;//opt为第二标尺最优值
vector<int>path, temppath;//一条最优的路径和临时的路径
void dfs(int v)//v为当前访问的结点
{
if (v == st)//如果到了叶子结点,即起始点
{
int value;//value为临时路径上的第二标尺的值
temppath.push_back(v);//将路径起始点加入到临时路径的最后面
//计算temmpath路径上的第二标尺value的值
if (value > optvalue)
{
optvalue = value;//更新第二标尺的值和最优路径
path = temppath;
}
temppath.pop_back();//删除刚刚加入的结点
return;
}
//if v != st
temppath.push_back(v);//当前访问的结点加入到临时路径temppath的后面
for (int i = 0; i < temppath.size(); i++)
{
int nex = pre[v][i];//对v的前驱结点进行递归访问 前驱结点pre[v][i]
dfs(nex);
}
temppath.pop_back();//遍历完所有的前驱结点 删除刚刚加入的结点
}
int value=0;//边权
for (int i = temppath.size() - 1; i > 0; i--)
{
int id = temppath[i],nextid = temppath[i-1];//当前结点为id,下一个结点为nextid
int nextint = temppath[i - 1];//循环条件为i>0
value += G[id][nextid];
//value增加从id到nextid的边权 这里G表示一个点到另一个点之间边权大小
}
int value = 0;//点权之和
for (int i = temppath.size()-1; i >= 0; i--)
{
int id = temppath[i];//循环条件为i>=0
value += w[id];//value增加id的点权
}
一条路径的边权或者点权进行计算
给出N个城市个M条道路 每条道路的花费和距离 起点和终点给定 求出最短距离,如果有多条距离最短,求最小花费的路径
#include<iostream>
#include<string>
#include<vector>
#include<Windows.h>
#include <conio.h>
#include<ctime>
#include<stack>
#include<cctype>
#include<cmath>
#include<stdio.h>
#include <windows.h>
#include<algorithm>
#include<cstring>
using namespace std;
int m_direction;
string str;
//使用狄杰特斯拉算法记录所有最短路径
const int maxn = 1000,inf=100000000;
int M, N,st,sd;//st起点 sd终点 N个城市编号为0~N-1 M条道路为无向边 给出M条道路的距离属性以及花费属性
int mincost=inf;
int d[maxn];
bool inq[maxn] = {
false };
vector<int> pre[maxn];//存放结点的前驱结点
int optvalue;//opt为第二标尺最优值
vector<int>path, temppath;//一条最优的路径和临时的路径
int distancee[maxn][maxn],dis;
int costt[maxn][maxn];//花费
void dijksra(int s)//s为起点
{
int u;
fill(d, d + maxn, inf);
d[s] = 0;//到自身的距离为0
for (int i = 0; i <N; i++)
{
u = -1;
int min = inf;//注意min初始化的位置是在循环里面 每次
for (int j = 0; j <N; j++)
{
if (inq[j] == false && d[j] < min)
{
u = j;
min = d[j];//先找到最小的d[u] u是下标
}
}
if (u == -1) return;//说明剩下的点和起始点不连通
inq[u] = true;//标记为已经访问过
for (int v = 0; v < N; v++)
{
if (inq[v] == false && distancee[u][v] != inf) {
if (d[u] + distancee[u][v] < d[v])
{
d[v] = d[u] + distancee[u][v];
pre[v].clear();
pre[v].push_back(u);
}
else if (d[u] + distancee[u][v] == d[v])
pre[v].push_back(u);
}
}
}
}
void dfs(int v)//v为当前访问的结点
{
if (v == st)//如果到了叶子结点,即起始点
{
int temcost = 0;//当前的花费之和
temppath.push_back(v);//将路径起始点加入到临时路径的最后面
for (int i = temppath.size() - 1; i > 0; i--)
{
int id = temppath[i], nextid = temppath[i - 1];//当前结点为id,下一个结点为nextid
//循环条件为i>0
temcost += costt[id][nextid];
//value增加从id到nextid的边权 这里G表示一个点到另一个点之间边权大小
}
if (temcost < mincost)
{
mincost=temcost;//更新第二标尺的值和最优路径
path = temppath;
}
temppath.pop_back();//删除刚刚加入的结点
return;
}
//if v != st
temppath.push_back(v);//当前访问的结点加入到临时路径temppath的后面
for (int i = 0; i < pre[v].size(); i++)
{
int nex = pre[v][i];//对v的前驱结点进行递归访问 前驱结点pre[v][i]
dfs(nex);
}
temppath.pop_back();//遍历完所有的前驱结点 删除刚刚加入的结点
return;
}
//4 5 0 3
//0 1 1 20
//1 3 2 30
//0 3 4 10
//0 2 2 20
//2 3 1 20
int main()
{
int huafei;
int i, j;
cin >> N >> M >> st >> sd;
fill(distancee[0], distancee[0] + maxn * maxn, inf);
fill(costt[0], costt[0] + maxn * maxn, inf);
for (int z = 0;z < M; z++)
{
cin >> i >> j;
cin >> distancee[i][j];
distancee[j][i]= distancee[i][j];
cin >> costt[i][j];
costt[j][i] = costt[i][j];
}
dijksra(st);
dfs(sd);
for (int i = path.size()-1; i >= 0; i--)
cout << path[i] << " ";
cout << endl;
cout << d[sd] << " " <<mincost;//输出最短距离和最小花费
}