我是靠谱客的博主 忧虑星月,最近开发中收集的这篇文章主要介绍6.最短路径(模板)一. Dijkstra算法二.bellman-ford算法三.spfa算法四.Floyd算法,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
最短路径
- 一. Dijkstra算法
- (1)Dijkstra求最短路 I
- (2)Dijkstra求最短路 II
- 二.bellman-ford算法
- (1)有边数限制的最短路
- 三.spfa算法
- (1)spfa求最短路
- (2)spfa判断负环
- 四.Floyd算法
- (1)Floyd求最短路
一. Dijkstra算法
(1)Dijkstra求最短路 I
题目来源: Dijkstra求最短路 I
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int g[N][N]; //为稠密阵所以用邻接矩阵存储
int dist[N]; //用于记录每一个点距离第一个点的距离
bool st[N]; //用于记录该点的最短距离是否已经确定
int n,m;
int Dijkstra()
{
memset(dist, 0x3f,sizeof dist); //初始化距离0x3f代表无限大
dist[1]=0; //第一个点到自身的距离为0
for(int i=0;i<n;i++) //有n个点所以要进行n次迭代
{
int t=-1; //t存储当前访问的点
//找到不在集合中距离最近的点,st[]=false表示不在集合中
for(int j=1;j<=n;j++) //这里的j代表的是从1号点开始
if(!st[j]&&(t==-1||dist[t]>dist[j])) //t==-1开始用到,dist[t]>dist[j])后几次用到
t=j;
st[t]=true;
for(int j=1;j<=n;j++) //依次更新每个点所到相邻的点路径值
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
if(dist[n]==0x3f3f3f3f) return -1; //如果第n个点路径为无穷大即不存在最低路径
return dist[n];
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g); //初始化图因为是求最短路径
//所以每个点初始为无限大
while(m--)
{
int x,y,z;
cin>>x>>y>>z;
g[x][y]=min(g[x][y],z); //如果发生重边的情况则保留最短的一条边
}
cout<<Dijkstra()<<endl;
return 0;
}
(2)Dijkstra求最短路 II
题目来源: Dijkstra求最短路 II
//稀疏图——邻接表
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef pair<int, int> PII; //<离起点的距离,节点编号>
const int N = 150010;
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
int n, m;
//在a节点之后插入一个b节点,权重为c
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int dijkstra()
{
//所有距离初始化为无穷大
memset(dist, 0x3f, sizeof dist);
//1号节点距离为0
dist[1] = 0;
//建立一个小根堆
priority_queue<PII, vector<PII>, greater<PII>> heap;
//1号节点插入堆
heap.push({0, 1});
while (heap.size())
{
//取出堆顶顶点
auto t = heap.top();
//并删除
heap.pop();
//取出节点编号和节点距离
int ver= t.second, distance = t.first;
//如果节点被访问过,则跳过
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
//取出节点编号
int j = e[i];
//dist[j]大于从t过来的距离
if (dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
heap.push({dist[j], j});
}
}
}
if (dist[n] == 0x3f3f3f3f)return -1;
return dist[n];
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
while (m--)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
cout << dijkstra() << endl;
return 0;
}
二.bellman-ford算法
(1)有边数限制的最短路
题目来源:有边数限制的最短路
#include<iostream>
#include<cstring>
using namespace std;
const int N = 510, M = 10010;
//把每个边保存下来即可
struct Edge
{
int a;
int b;
int w;
} e[M];
int dist[N];
int back[N];//备份数组防止串联
int n, m, k;//k代表最短路径最多包涵k条边
int bellman_ford()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
//k次循环
for (int i = 0; i < k; i++)
{
memcpy(back, dist, sizeof dist);
//遍历所有边
for (int j = 0; j < m; j++)
{
int a = e[j].a, b = e[j].b, w = e[j].w;
dist[b] = min(dist[b], back[a] + w);
//使用backup:避免给a更新后立马更新b, 这样b一次性最短路径就多了两条边出来
}
}
if (dist[n] > 0x3f3f3f3f / 2) return -1;//因为存在负权回路
else return dist[n];
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < m; i++)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
e[i] = {a, b, w};
}
int res = bellman_ford();
if (res == -1) puts("impossible");
else cout << res;
return 0;
}
三.spfa算法
(1)spfa求最短路
题目来源:spfa求最短路
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
int h[N], e[N], w[N], ne[N], idx;
int n, m;
queue<int> q;//存储待更新的点
int st[N];//ture在队列,false不在队列
int dist[N];
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int spfa()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
q.push(1);
st[1] = true; //点在队列为true
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false; //点不在队列为false
//遍历t的所有临边
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i]) //需要更新
{
dist[j] = dist[t] + w[i];
if (!st[j]) //如果J不在队列,就加入队列,否则跳过
{
st[j] = true;
q.push(j);
}
}
}
}
if (dist[n] == 0x3f3f3f3f ) return -1; //不理解,存在负权路
else return dist[n];
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
int t = spfa();
if (t == -1) cout << "impossible" << endl;
else cout << t << endl;
}
(2)spfa判断负环
题目来源:spfa判断负环
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
int h[N], e[N], w[N], ne[N], idx;
int n, m;
queue<int> q;
int st[N], dist[N], cnt[N];
void add(int a, int b, int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
int spfa()
{
memset(dist, 0x3f, sizeof dist);
//因为不知道负环是在1-n的路径上,还是其他路径,需要将所有点加入队列
for (int i = 1; i <= n; i++)
{
q.push(i);
st[i] = true;
}
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if (!st[j])
{
st[j] = true;
q.push(j);
}
// n点,n-1条边
// 根据抽屉原理,说明经过某个节点两次,则说明有环
if (cnt[j] >= n) return true;
}
}
}
return false;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
if (spfa()) puts("Yes");
else puts("No");
}
四.Floyd算法
(1)Floyd求最短路
题目来源:Floyd求最短路
#include <iostream>
using namespace std;
const int N = 210, M = 2e+10, INF = 1e9;
int n, m, k, x, y, z;
int d[N][N];//d[x][y]表示X到Y的最短距离
void floyd()
{
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
int main()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i == j) d[i][j] = 0;//x到x的最短距离为0
else d[i][j] = INF;
while(m--)
{
cin >> x >> y >> z;
//注意保存最小的边
d[x][y] = min(d[x][y], z);
}
floyd();
while(k--)
{
cin >> x >> y;
if(d[x][y] >= INF/2) puts("impossible");
//由于有负权边存在所以约大过INF/2也很合理
else cout << d[x][y] << endl;
}
return 0;
}
最后
以上就是忧虑星月为你收集整理的6.最短路径(模板)一. Dijkstra算法二.bellman-ford算法三.spfa算法四.Floyd算法的全部内容,希望文章能够帮你解决6.最短路径(模板)一. Dijkstra算法二.bellman-ford算法三.spfa算法四.Floyd算法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复