特殊最短路
- 树:直接起点dfs搜索到终点即可
- 有向无环图:拓扑排序,删掉每一个点时更新后继的最短距离
- 边权全部为相等:bfs
单源最短路
- 从一个点出发到其它顶点的最短路径长度
- 基本操作:松弛
这样的(u,v)称为紧的,可以对它进行松弛
dijkstra
- 不能存在负边,每个边会被访问一次,每个边都有可能进一次优先队列
&preview=true)
- dis数组初值赋为极大
- 起点dis为0
- 计算与s相邻的所有点的dis——

- 取还没算出最短路的点中dis最小的点u,它的最短路就是

- 对于u相连的所有点v如果能松弛,更新

- 重复4,5直到所有点求完
#include<bits/stdc++.h>
using namespace std;
typedef struct{
int t,l,nxt;
}E;
struct ty{
int x,dis;
bool operator < (const ty &a) const{
return dis > a.dis;
}
};
E edge[101010];
int n,m,s,t;
int dis[1010],vis[1010];
int head[1010];
int cnt=0;
void insert(int x,int y,int val){
edge[++cnt].t=y;
edge[cnt].l=val;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
priority_queue<ty> q;
int dijkstra(int st,int to){
dis[st]=0;
ty tmp;
tmp.x=s,tmp.dis=0;
q.push(tmp);
while(!q.empty()){
ty tp=q.top();
q.pop();
if(vis[tp.x]) continue;
vis[tp.x]=1;
for(int i=head[tp.x];i!=-1;i=edge[i].nxt){
int to=edge[i].t;
if(vis[to]) continue;
if(dis[to]>dis[tp.x]+edge[i].l){
dis[to]=dis[tp.x]+edge[i].l;
ty tp2;
tp2.x=to,tp2.dis=dis[to];
q.push(tp2);
}
}
}
if(dis[t]>=0x3f3f3f3f) return -1;
else return dis[to];
}
int main(){
cin >> n >> m >> s >> t;
memset(head,-1,sizeof(head));
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=m;i++){
int a,b,v;
cin >> a >> b >> v;
insert(a,b,v);
insert(b,a,v);
}
cout << dijkstra(s,t) << endl;
return 0;
}
Bellman-Ford
- 可以有负边,不能有负环(环上所有边权值和不能为负)
- 枚举所有点,能松弛就松弛,直到所有点都不能松弛
//邻接矩阵,O(n^3)
while(b){
b=false;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[j]+val[j][i]<dis[i]){
dis[i]=dis[j]+val[j][i];
b=true;
}
}
}
}
SPFA--BF的队列优化(O(KM),K为平均入队次数,只有有负权才用)
- dis数组表示距离,fa数组表示s到i的最短路径中到i的前一个点,fa初值为0,dis初值为极大,
dis[s]=0
- 维护一个队列,存放需要迭代的点,初始时队列里只有一个s
- 维护一个bool数组,记录每一个点是否在队列中
- 每次取出队首v,枚举v发出的边v->u,长度为len,如果
dis[v]+len<dis[u]
则改进dis[u]
同时,fa[u]=v
- 由于s到u的距离变小了,所以u有可能改进其它点,所以如果u不在队列中,将u弹入队尾
- 循环这个过程,直到队列为空,如果任意一个点入队次数超过n,则存在负权环
#include<bits/stdc++.h>
using namespace std;
typedef struct{
int t,l,nxt;
}E;
E edge[101010];
int head[101010];
int cnt;
int n,m,s,t;
int dis[1010],vis[1010];
void insert(int x,int y,int val){
edge[++cnt].t=y;
edge[cnt].l=val;
edge[cnt].nxt=head[x];
head[x]=cnt;
}
queue<int> q;
int spfa(int s,int t){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=edge[i].nxt){
int y=edge[i].t;
if(dis[y]>dis[x]+edge[i].l){
dis[y]=dis[x]+edge[i].l;
if(!vis[y]){
q.push(y);
vis[y]=1;
}
}
}
}
if(dis[t]>=0x3f3f3f3f) return -1;
else return dis[t];
}
int main(){
cin >> n >> m >> s >> t;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++){
int a,b,v;
cin >> a >> b >> v;
insert(a,b,v);
insert(b,a,v);
}
cout << spfa(s,t) << endl;
return 0;
}
多源最短路
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&&j!=k&&k!=i){
if(f[i][k]+f[k][j]<=f[i][j]){
f[i][j]=f[i][k]+f[k][j];
}
}
}
}
}