最短路
朴素版Dijkstra算法(适用于稠密图)
思路
- 初始化距离数组和邻接矩阵(无穷大)
- 处理重边问题在输入取最小值
- 每次找到一个最小的未更新的答案点
- 将其连边答案全部更新
代码实现如下:
#include<bits/stdc++.h>
using namespace std;
const int N=520,INF=0x3f3f3f3f;
int n,m;
int g[N][N],dis[N];
bool st[N];
int dijkstra()
{
dis[1]=0;//每个点到一号点的最短距离
//如需求到s点的一开始将dis[s]定义为0即可
for(int i=0;i<n-1;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dis[t]>dis[j])) t=j;//找到当前未更新的最小点
}
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[t]+g[t][j]);//将t连接的点都更新最短距离
st[t]=true;
}
if(dis[n]==0x3f3f3f3f)return -1;//1~n之间不连通,无法构成路径,也就没有最短距离
return dis[n];
}
int main()
{
cin>>n>>m;
fill(g[0],g[0]+N*N,INF);
fill(dis,dis+N,INF);
while(m--)
{
int x,y,c;
cin>>x>>y>>c;
g[x][y]=min(g[x][y],c);//处理重边
}
cout<<dijkstra()<<endl;
return 0;
}
堆优化版Dijkstra算法(适用于稀疏图)
优点:
- 堆可以动态维护一个集合中的最小值
- 堆动态支持插入,删除,修改一个数
优化部分:
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dis[t]>dis[j])) t=j;//找到当前未更新的最小点
}
//每次寻找一个最小值可以用堆来维护一个最小值
//复杂度从O(n)->O(1)
////////////////////////////////////////////
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[t]+g[t][j]);//将t连接的点都更新最短距离
//每次将点更新在堆中修改复杂度为mlogm
//复杂度从O(n)->O(mlogm)
//////////////////////////////////////////////
//总体复杂度从O(n^2)->O(mlogm)
代码实现:
#include<bits/stdc++.h>
#define PII pair<int,int>
using namespace std;
const int N=1e6+10,INF=0x3f3f3f3f;
int n,m;
int h[N],e[N],ne[N],idx;
int dis[N],w[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra()
{
fill(dis,dis+N,INF);
dis[1]=0;
priority_queue<PII,vector<PII>,greater<PII> > heap;//优先队列默认大根堆,这样子写可以维护小根堆,pair<int,int>第一个值存数值,第二个值存下标
heap.push({0,1});
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];
if(dis[j]>dis[ver]+w[i])//有更短路就替换
{
dis[j]=dis[ver]+w[i];
heap.push({dis[j],j});//将新的方案加入到队列中
}
}
}
//队列为空即走完整个图
if(dis[n]==INF)return -1;
return dis[n];
}
int main()
{
cin>>n>>m;
fill(h,h+N,-1);//将头结点数组全部初始化成-1
while(m--)
{
int x,y,c;
cin>>x>>y>>c;
add(x,y,c);
}
cout<<dijkstra()<<endl;
return 0;
}
SPFA算法(适用于稀疏图)
Bellman-Ford太呆
优点:
- 每次只更新与结点有关点的最小距离
例题:SPFA求最短路
代码实现:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
int h[N], e[N], ne[N], w[N], idx;//稀疏图用邻接表来存图
int n, m;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int spfa()
{
fill(dist, dist + N, INF);//先将每个到源点的距离初始化成正无穷
dist[1] = 0;
queue<int> q;
q.push(1);
st[1] = true;
while (q.size())
{
int t = q.front();
q.pop();
st[t] = false; //出队了
for (int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])//更新t结点的所有距离
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
q.push(j);//更新的点第一次访问就进度,后面可能还能再利用其更新其他点
st[j] = true;
}
}
}
}
return dist[n];
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while (m--)
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
int t = spfa();
if (t == INF)//如果到n点还无法更新距离说明无法连通
puts("impossible");
else
cout << t << endl;
return 0;
}

浙公网安备 33010602011771号