目录
2.memcpy()函数:memcpy_百度百科,memcpy函数效率很高
1.spfa算法实际上是对Bellman-Ford算法的一个优化
原理:对于一个n个点,m条边的有向图,如果到达一个点的最短路大于等于n,那么就一定存在负环。
1.朴素dijkstra算法
AC代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 510;
int g[N][N], dist[N]; //邻接矩阵,到节点i的最短路径
bool st[N]; //判断i点是否已经找到了最短路径
int n, m;
void djikstra()
{
memset(dist, 0x3f, sizeof dist); //初始化所有最短路径为最大值
dist[1] = 0; //以节点1为起点,所以到节点1的最短距离为0
for(int u = 1; u <= n; u ++ )
{
int k = -1;
for(int i = 1; i <= n; i ++ ) //找到当前状态下所有最短路径中最短的一个
if((k == -1 || dist[k] > dist[i]) && !st[i])
k = i;
st[k] = true; //标记这个节点的最短路径已经找到了
for(int i = 1; i <= n; i ++ ) //用这个最短路径更新所有最短路径
dist[i] = min(dist[i], dist[k] + g[k][i]);
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
for(int i = 0; i < m; i ++ )
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = min(g[a][b], c); //通过这一步可以忽略掉重边并取得最小的边值
}
djikstra();
if(dist[n] == 0x3f3f3f3f) puts("-1"); //要判断是否有路
else cout << dist[n] << endl;
return 0;
}
2.堆优化版dijkstra算法
AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 160010;
int h[N], ne[N], e[N], w[N], idx;
int dist[N];
bool st[N];
int n, m;
void add(int a, int b, int c)
{
w[idx] = c; //在赋权值的时候,要在idx++之前!
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void djikstra()
{
memset(dist, 0x3f, sizeof dist);
priority_queue<PII, vector<PII>, greater<PII> > heap;
heap.push({0,1}); //(距离,下标号)
dist[1] = 0;
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]; //我们在邻接表存的是下标,通过e[i]得到顶点
if(dist[j] > distance + w[i]) //如果路径可以被优化
{
dist[j] = distance + w[i]; //更新路径
heap.push({dist[j], j}); //假如队列
}
}
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while(m -- )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
djikstra();
if(dist[n] == 0x3f3f3f3f) puts("-1");
else cout << dist[n] << endl;
return 0;
}
分析
- 使用优先级队列
在使用前需要先搞清楚优先级队列的时间复杂度,往一个长度为n的优先级队列中插入一个元素时间复杂度是O(logn)。那么把n个元素插入一个空的优先级队列中时间复杂度就为O(nlogn)。 - O(Log n)
如果在一个大小为n的循环中,循环变量是指数级的递增或递减,这个循环的复杂度就为O(Log n). - 堆优化,主要优化的是找当前状态下的最短的路径的时间,在朴素算法中,是通过一个for循环完成,时间复杂度是线性的,但是在堆优化版本中,使用优先队列可以在常数时间内取出这个最短的路径,即队头,不过需要注意的是维护优先队列的时间复杂度是为O(N)的
- 优先队列的实现方式通过一个pair,储存最短路和下标