最短路算法(三类)
Floyd算法
我们定义一个数组 dis[k][x][y] ,表示只允许经过结点 V1 到 Vk ,结点 x 到结点 y 的最短路长度。
核心算法,时间复杂度为O(n^3),容易卡tle。
for (k = 1; k <= n; k++) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
//比较从i直接到j点的距离和从i到k再到j的距离取小,然后保存在dis[i][j]中
}
}
}
Dijkstra算法
只适用于非负权图,但是时间复杂度非常优秀。也是用来求单源最短路径的算法。主要思想是,将结点分成两个集合:已确定最短路长度的,未确定的。
一开始第一个集合里只有 S (源点)。
然后重复这些操作:
1.对那些刚刚被加入第一个集合的结点的所有出边执行松弛操作。
2.从第二个集合中,选取一个最短路长度最小的结点,移到第一个集合中。
对那些刚刚被加入第一个集合的结点的所有出边执行松弛操作。从第二个集合中,选取一个最短路长度最小的结点,移到第一个集合中。直到第二个集合为空,算法结束。
核心算法 能用优先队列优化
原版
void dj(int s, int n){
memset(d, inf, sizeof(d));//从s点到i点的距离
memset(vis, false, sizeof(vis));//集合
d[s]=0;//s到s点的距离为0
for(int i=1;i<n;i++){
int x=0;
for(int j=1;j<=n;j++){//从1遍历到n
if(!vis[j]&&(x==0||d[j]<d[x]))x=j;
//!vis[j]表示这个点还不在已标记的集合内
//x=0||d[j]<d[x]表示取距离最短的
//x=j更新最短距的点
}
vis[x]=true;//将集合外的最短距的点放入集合
for(int y=1;y<=n;y++){//再次遍历
d[y]=min(d[y], d[x]+dis[x][y]);
//想floyd算法一样,将s到y的现有距离与s到x再到y的距离比较取小
}
}
}
优先队列优化版(比较懒直接用学长的板子了)
const int inf=0x3f3f3f3f;
int head[11111], ver[44444], edge[44444], Next[44444], d[11111];
bool vis[11111];
int tot;
priority_queue<pair<int ,int>>q;
void add(int x, int y, int z){
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dj(int s, int n){
memset(d, inf, sizeof(d));
memset(vis, false, sizeof(vis));
d[s]=0;
q.push(make_pair(0, s));
while(!q.empty()){
int x=q.top().second;
q.pop();
if(vis[x])continue;
vis[x]=true;
for(int i=head[x];i;i=Next[i]){
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z){
d[y]=d[x]+z;
q.push(make_pair(-d[y], y));
}
}
}
}
Bellman-Ford(SPFA)算法
个人觉得像极了Dijkstra算法的优先队列优化版
核心算法(学长板子,求学长放过)
const int inf=0x3f3f3f3f;
int head[11111], ver[44444], edge[44444], Next[44444], d[11111];
bool vis[11111];
int tot;
priority_queue<pair<int ,int>>q;
void add(int x, int y, int z){
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void spfa(){
memset(d, 0x3f, sizeof(d));
memset(v, 0, sizeof v);
queue<int>q;
d[1]=0;
v[1]=1;
q.push(1);
while(!q.empty()){
int x=q.front();
q.pop();
v[x]=0;
for(int i=head[x];i;i=Next[i]{
int y=ver[i],z=edge[i];
if(d[y]>d[x]+z{
d[y]=d[x]+z;
if(!v[y])q.push(y),v[y]=1;
}
}
}
}
总结
以上三种算法虽然都归结在最短路算法里,但是并不仅限于最短路径这类题,而是可以听过一些修改,得到某些路段的权值或者权值和(有待提升我)