1.Dijkstra邻接矩阵实现(时间少)
- 时间复杂度 O(n²)
- 空间复杂度 O(n²)
- 不能出现负权边。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
int map[110][110];//这就是map数组,存储图
int dist[10010];//dist数组,存储距离
int book[10010];//book[i]代表这个点有没有被当做源点去搜索过,1为有,0为没有。这样就不会重复搜索了。
int n,m;
int path[110];//存路径
void dijkstra(int x,int y)//参数是源点编号
{
memset(dist,88,sizeof(dist));//把dist数组附最大值(88不是十进制的88,其实很大)
int start=x;//先从源点搜索
book[start]=1;//标记源点已经搜索过
for(int i=1;i<=n;i++)
{
dist[i]=min(dist[i],map[start][i]);//先更新一遍
}
int k=0;
for(int i=1;i<=n-1;i++)
{
int minn=9999999;
for(int j=1;j<=n;j++)
if(book[j]==0 && minn>dist[j])
{
minn=dist[j];
start=j;//找到离源点最近的点,然后把编号记录下来,用于搜索。
}
book[start]=1;
for(int j=1;j<=n;j++)
{
if(dist[start]+map[start][j]<dist[j])
{
if(j==y)//存路径,只存x到y的
{
path[k]=start;
k++;
}
dist[j]=dist[start]+map[start][j];//存距离
}
}
//dist[j]=min(dist[j],dist[start]+map[start][j]);//以新的点来更新dist。
}
}
void outpath(int x,int y)
{
cout<<x<<"->";
for(int i=0;path[i]!=0;i++)
cout<<path[i]<<"->";
cout<<y<<endl;
}
int main()
{
cin>>n>>m;//n个点,m个边
memset(map,88,sizeof(map));
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
map[a][b]=c;//有向图
//map[a][b]=map[b][a]=c;//无向图
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)
map[i][j]=0;
int x=4,y=3;//x起点,y终点
dijkstra(x,y);//以x为源点,计算x到所有点的最短距离
for(int i=1;i<=n;i++)
cout<<dist[i]<<" ";
cout<<endl;
outpath(x,y);
}
输入
//点数,边数
//a点,b点,ab距离
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
输出
//4到所有点的最短距离
//4到3的最短路径
5 7 10 05 7 10 0
4->1->2->3
2.Dijkstra邻接表实现(空间少)
- 时间复杂度O(n*m)
- 空间复杂度 O(m)
- 不能出现负权边。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
int value[10010],to[10010],next[10010];
int head[10010],total;
int book[10010];
int dist[10010];
int n,m;
void adl(int a,int b,int c)
{
total++;
to[total]=b;
value[total]=c;
next[total]=head[a];
head[a]=total;
}
void dijkstra(int u)
{
memset(dist,88,sizeof(dist));
memset(book,0,sizeof(book));
dist[u]=0;
for(int i=1;i<=n;i++)
{
int start=-1;
for(int j=1;j<=n;j++)
if(book[j]==0 && (dist[start]>dist[j] || start==-1))
start=j;
book[start]=1;
for(int e=head[start];e;e=next[e])
dist[to[e]]=min(dist[to[e]],dist[start]+value[e]);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
adl(a,b,c);
}
dijkstra(1);
for(int i=1;i<=n;i++)
cout<<dist[i]<<" ";
}
输入同上
输出0 2 5 4
3.Bellman-ford
- 时间复杂度O(n*m)
- 空间复杂度 O(m)
- 可以出现负权边。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
int dist[10010];
//origin[i]表示编号为i这条边的起点编号,如origin[4]=2
//destination[i]表示编号为i这条边的终点编号,如origin[5]=5
//value[i]表示编号为i这条边的权值,如value[3]=-6
int origin[10010],destination[10010],value[10010];
int n,m;
void Bellman_ford(int a)
{
memset(dist,88,sizeof(dist));//赋初始值
dist[a]=0;
for(int i=1;i<=n-1;i++)//更新n-1次
for(int j=1;j<=m;j++)//更新每一条边
dist[destination[j]]=min(dist[destination[j]],dist[origin[j]]+value[j]);//判断是否更新
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>origin[i]>>destination[i]>>value[i];
Bellman_ford(1);
for(int i=1;i<=n;i++)
cout<<dist[i]<<" ";
}
输入输出同上