实现弗洛伊德算法和迪杰斯特拉算法求单源最短路径
一、迪杰斯特拉算法:
默认源点为1,d【x】:源点到x的距离;
(x,y,z)表示x->y的边权为z,即dist[x][y]=z;
1.初始化源点到源点的距离d[1]为0,到其余各点的距离为正无穷。
2.找出一个未被标记的、d[x]最小的节点x,然后标记该节点x。
3.扫描节点x的所有出边(x,y,z),若d[y]>d[x]+z,则使用d[x]+z更新d[y]。
4.重复上述2、3操作,直到所有节点都被标记。
注意:该算法只使用于边权为非负数的情况。最终得到源点到各个点的最短路径。
代码:
#include<bits/stdc++.h>
using namespace std;
//dijkstra
const int N=10010;
int head[N],next[N],ver[N],edge[N],d[N];//ver终点,edge边权 ,d起点到该点的距离
bool v[N];
int tot,n,m;
//利用大根堆维护当前最小距离,并用最小距离更新其他节点
priority_queue< pair<int,int> >q;
//(x,y),权值为z
void add(int x,int y,int z){
ver[++tot]=y;
edge[tot]=z;
next[tot]=head[x];//此时head保存的是上一次的tot
head[x]=tot;
}
void dijkstra(){
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
//初始化d[1]=0;
d[1]=0;
q.push(make_pair(0,1)); //d,y
while(q.size()){
int x=q.top().second;
q.pop();
if(v[x])continue;
for(int i=head[x];i;i=next[i]){
int y=ver[i],dxy=edge[i];//
if(d[y]>d[x]+dxy){
d[y]=d[x]+dxy;
q.push(make_pair(-d[y],y));//大根堆转换成小根堆,-d[y]
}
}
}
}
int main(){
cin>>n>>m;//n个点,m个边
//有向图
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);//构建邻接表
}
dijkstra();
for(int i=1;i<=n;i++){
printf("%d\n",d[i]);
}
return 0;
}
二、弗洛伊德算法:
邻接矩阵tim[x][y]表示的是x->y的边权。n个点,m条边
1.遍历n个顶点,作为中转点k。
2.对于每个中转点,当i!=j时,更新d[i][j]=min(d[i][j],d[i][k]+d[k][j])
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
int tim[N][N];//Floyd的临界数组
void Floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j){
tim[i][j]=min(tim[i][j],tim[i][k]+tim[k][j]);
}
}
}
}
}
int main(){
cin>>n>>m;//n个点,m个边
//有向图
memset(tim,0x3f,sizeof(tim));
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
tim[x][y]=z;//构建临界数组
}
Floyd();
for(int i=1;i<=n;i++){
printf("%d\n",tim[1][i]);
}
return 0;
}