Dijkstra算法
Ballman_ford算法
Spfa算法
Floyd算法
时间复杂度:$O(n^2)$
数据量比较密集时:数据存储用邻接矩阵g[][]
较大值MAX选用0x3f3f3f3f
:32bit中通常int最大值为0x7fffffff
,但是此处需要对MAX进行加法,0x7fffffff + 3
为负数,显然不符合最短路径算法中的松弛操作,因此,如果能满足无穷大加无穷大结果依然是无穷大
就完美符合松弛操作。0x3f3f3f3f
的十进制是1061109567,是 1 0 9 10^9 109级别的,而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
0x3f3f3f3f
是一个很有用的数值,它是满足以下两个条件的最大整数。
1、整数的两倍不超过0x7f7f7f7f
,即int能表示的最大正整数。
2、整数的每8位(每个字节)都是相同的。
我们在程序设计中经常需要使用memset(a, val, sizeof a)
初始化一个数组a,该语句把数值 val(0x00~0xFF)填充到数组a 的每个字节上,所以用memset只能赋值出“每8位都相同”的 int。
当需要把一个数组中的数值初始化成正无穷时,为了避免加法算术上溢出或者繁琐的判断,我们经常用memset(a, 0x3f, sizeof(a))
给数组赋0x3f3f3f3f
的值来代替。
朴素Dijkstra算法
#include
using namespace std;
#include
int n,m;
//稠密图用邻接矩阵
const int N= 510, MAX = 0x3f3f3f3f;
int g[N][N];
int d[N];//节点间距离矩阵,当前点到1的距离数组
bool st[N];//状态确认数组,true表示当前状态已经确认为最短值,不可再修改
void Dijkstra(){
//初始化
memset(d, MAX, sizeof d);
d[1]=0;//st[1]=true;
//遍历n次,每次确认一个节点
for(int i=0;i<n;i++){
//找到距离最短的路径点
int min_idx, min_dis = MAX;
for(int j=1;j<=n;j++){
//当前点状态为确定 && 当前点到1的距离小于min_dis
if(!st[j] && d[j]<min_dis){
min_idx = j;
min_dis = d[j];
}
}
st[min_idx]=true;
//更新距离
for(int j=1;j<=n;j++){
d[j] = min(g[min_idx][j]+d[min_idx], d[j]);
}
}
}
int main(){
cin>>n>>m;
memset(g, MAX, sizeof g);
int a, b, v;
while(m--){
cin>>a>>b>>v;
g[a][b]=min(v,g[a][b]);
}
Dijkstra();
if(d[n]==MAX) cout<<-1;
else cout<<d[n];
return 0;
}
时间复杂度:$O(mlogm)$
堆优化版的dijkstra是对朴素版dijkstra进行了优化,在朴素版dijkstra中时间复杂度最高的寻找距离
最短的点O(n^2)可以使用最小堆优化。
#include
using namespace std;
#include
#include
//稀疏图的Dijkstra算法
//稠密图用邻接矩阵,稀疏图用邻接表
int n, m;
const int N=150010 , MAX=0x3f3f3f3f;
int idx, e[N], h[N], ne[N], v[N];
int d[N];//存储当前点到1的最短距离
bool st[N];//存储当前点是否确认
typedef pair<int,int> PII;
void add(int a, int b, int c){
e[idx]=b;
v[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void Dijkstra(){
memset(d, MAX, sizeof d);
//初始化起点
d[1]=0;
priority_queue<PII , vector<PII>, greater<PII>> heap;//小顶堆
heap.push({0,1});//起点放入
//
while(heap.size()){
//查找距离最近的且未确认的点
PII minn = heap.top();
heap.pop();
int min_idx = minn.second, min_dis = minn.first;
if(st[min_idx]) continue;//特:如果当前点已经确认则continue
//更新新起点
st[min_idx] = true;
//更新新起点连通点的最短距离
for(int i = h[min_idx]; i!=-1; i=ne[i]){
int j=e[i];
if(d[j]>min_dis+v[i]){
d[j]=min_dis+v[i];
heap.push({d[j],j});
}
}
}
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
int a,b,c;
while(m--){
cin>>a>>b>>c;
add(a,b,c);
}
Dijkstra();
if(d[n] == MAX) cout<< -1;
else cout<<d[n];
return 0;
}