Floyd算法原理
Floyd算法是一个经典的动态规划算法,它又被称为插点法。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。Floyd算法是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,算法目标是寻找从点i到点j的最短路径。
从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,算法假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,算法检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。
P3371 【模板】单源最短路径(弱化版)
单源最短路,我首先想到的就是Floyd算法,二话不说把代码敲上,但是只拿了七十分,有三个点MLE了,内存太大了
#include<bits/stdc++.h>
using namespace std;
int a[10009][10009];
int main(){
int n,m,k;
scanf("%d %d %d",&n,&m,&k);
int x,y,z;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=2147483647;
}
}
for(int i=0;i<m;i++){
scanf("%d %d %d",&x,&y,&z);
a[x][y]=min(a[x][y],z);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
if(a[j][i]<2147483647&&a[i][k]<2147483647){
a[j][k]=min(a[j][i]+a[i][k],a[j][k]);
}
}
}
}
a[k][k]=0;
for(int i=1;i<=n;i++){
printf("%d ",a[k][i]);
}
return 0;
}
迪杰斯特拉算法
假如我要求从A点到D点的最短路径,我们用肉眼可以很快速找出A–>C–>E–>D就是A点到D点的最最短路径,可是计算机没有肉眼,肉眼也解决不了一些很复杂的图路径问题,这时候我们就要借助计算机了,所以写程序就是要用计算机的思维去考虑问题。
迪杰斯特拉算法是一个按路径长度递增的次序产生最短路径的算法,它不仅能找到指定顶点之间的最短路径还可以把图中其他顶点最短路径一并求出来,理解这一点很重要,因为这反过来恰恰就是迪杰斯特拉算法的核心——在已经找到的最短路径点的基础上找下一个目标点,直到图中所有点被找过一遍。
从上面这段话我们可以得到几个很重要的信息
1.使用该算法的图应该是连通图
2.迪杰斯特拉算法是一个走一步看一步的算法,后面点的最短路径来源于与之相连的
上一个点;
3.图中所有的点只需要遍历一遍
可以说整个算法就是基于上面几个条件产生的,迪杰斯特拉算法的优点也在于这,只需要遍历一遍
所有的点便可以产生最短路径,所以不仅可以使算法时间复杂度降低,并且能得到其他点的最短路径。
具体实现
整个算法围绕那三点产生所以我们给满足这三点准备条件,
条件一第一条可以由自己选择一个连通图实现;
条件二第二条我们可以申请一个图中顶点数目大小的数据,用来保存目标点到各个顶点的最小权值,这里由于图中名字是大写英文字母所以我们可以让A(要求的最短路径的头)占用数组下标为0这个位置,以此类推
用迪杰斯特拉算法对付上面那题试试看
#include<bits/stdc++.h>
using namespace std;
int a[10009][10009];
bool vis[10009];
int dis[10009];
#define intf 2147483647
int main(){
int n,m,s;
scanf("%d %d %d",&n,&m,&s);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)a[i][j]=0;
else a[i][j]=intf;
}
}
int x,y,z;
for(int i=1;i<=m;i++){
scanf("%d %d %d",&x,&y,&z);
a[x][y]=min(a[x][y],z);
}
for(int i=1;i<=n;i++){
dis[i]=a[s][i];
}
vis[s]=true;
for(int i=1;i<=n-1;i++){
int minn=intf;
int u;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]<minn){
minn=dis[j];
u=j;
}
}
vis[u]=true;
for(int j=1;j<=n;j++){
if(a[u][j]<intf){
if(dis[j]>dis[u]+a[u][j])dis[j]=dis[u]+a[u][j];
}
}
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
return 0;
}
也是拿到了70分的成绩
好不容易搞定了两个算法,但是这道题还需要用另一个存储方式,链式前向星,明天再来