单源最短路径
Floyd
思想 :枚举
时间复杂度: O ( n 3 ) O(n^3) O(n3) , 空间复杂度: O ( n 2 ) O(n^2) O(n2)
适用条件 : 不能有负环,且必须存在最短路
for(int k = 1; k <= n; k++){
for(int x = 1; x <= n; x++){
for(int y = 1; y <= n; y++){
f[x][y]= min(f[x][y], f[x][k]+f[k][y]);
}
}
}
Dijkstra
思想 :类似于 Prim ,不断找到耗费最小的点,进行标记,直到达到目标
时间复杂度: O ( n 2 ) O(n^2) O(n2) , 空间复杂度: O ( m l o g m ) O(m log m) O(mlogm)
const int inf=0x3f3f3f3f; //代表无穷大。
const int maxn=100;//最大顶点数
int n,m;//n个顶点,m条边。
bool visited[maxn];//判断是否确定到源点的最终最短距离。
int graph[maxn][maxn];//带权图
int dis[maxn];//顶点到源点的最短距离。
int start,goal;//起点与目标点。
void init(){
memset(visited,false,sizeof(visited));
for(int i=1;i<=n;i++){
dis[i]=graph[start][i];//初始化dis数组。
}
}
void dijkstra(){
//源点为源点start。
int minn;//记录每趟最短路径中最小的路径值。
int pos;//记录得到的minn所对应的下标。
init();//调用初始化函数。
visited[start]=true;
for(int i=1;i<=n;i++){
//将n个顶点依次加入判断。
minn=inf;
for(int j=1;j<=n;j++){
if(!visited[j]&&dis[j]<minn){
minn=dis[j];
pos=j;
}
}
//经过这趟for循环后我们找到的就是我们想要的点,可以确定这点到源点的最终最短距离了。
visited[pos]=true;//我们将此点并入已知集合。
//接下来就是更新dis数组了,也就是当前最短距离,这都是针对还没有并入已知集合的点。
for(int j=1;j<=n;j++){
if(!visited[j]&&dis[j]>dis[pos]+graph[pos][j])
dis[j]=dis[pos]+graph[pos][j];
}
}
//退出循环后,所有的点都已并入已知集合中,得到的dis数组也就是最终最短距离了。
cout<<dis[goal]<<endl;//输出目标点到源点的最短路径长度。
}
Dijkstra(优先队列)
思想 :利用最小堆维护最小值,不用再去循环枚举找出最小值。
时间复杂度: M l o g M MlogM MlogM
typedef pair<int,int> pdd;
int head[maxn], dis[maxn];
bool vis[maxn];
struct Edge{
itn u,v,w;
int nex;
}e[maxm];
inline void add(int a,int b,int c)
{
e[++cnt].u=a;
e[cnt].v=b;
e[cnt].w=c;
e[cnt].nex=head[a];
head[a]=cnt;
}
priority_queue<pdd,vector<pdd>,greater<pdd>> q;
void dijkstra()
{
while(!empty())
{
pdd t = q.top();
q.pop();
int now = t.second;
if(vis[now])
continue;
vie[now]=true;
for(int i = head[now]; i; i = e[i].nex)
{
int to = e[i].v;
if(dis[to]>dis[now]+e[i].w)
{
dis[to]= dis[now] + e[i].w;
q.push({dis[to],to});
}
}
}
}