1.
单源点的最短路径问题:给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。
我们用一个例子来具体说明迪杰斯特拉算法的流程。
定义源点为 0,dist[i]为源点 0 到顶点 i 的最短路径。其过程描述如下:
步骤 | dist[1] | dist[2] | dist[3] | dist[4] | 已找到的集合 |
---|---|---|---|---|---|
第 1 步 | 8 | 1 | 2 | +∞ | {2} |
第 2 步 | 8 | × | 2 | 4 | {2, 3} |
第 3 步 | 5 | × | × | 4 | {2, 3, 4} |
第 4 步 | 5 | × | × | × | {2, 3, 4, 1} |
第 5 步 | × | × | × | × | {2, 3, 4, 1} |
第 1 步:从源点 0 开始,找到与其邻接的点:1,2,3,更新dist[]数组,因 0 不与 4 邻接,故dist[4]为正无穷。在dist[]中找到最小值,其顶点为 2,即此时已找到 0 到 2 的最短路。
第 2 步:从 2 开始,继续更新dist[]数组:2 与 1 不邻接,不更新;2 与 3 邻接,因0→2→3比dist[3]大,故不更新dist[3] ;2 与 4 邻接,因0→2→4比dist[4]小,故更新dist[4]为 4。在dist[]中找到最小值,其顶点为 3,即此时又找到 0 到 3 的最短路。
第 3 步:从 3 开始,继续更新dist[]数组:3 与 1 邻接,因0→3→1比dist[1]小,更新dist[1]为 5;3 与 4 邻接,因0→3→4比dist[4]大,故不更新。在dist[]中找到最小值,其顶点为 4,即此时又找到 0 到 4 的最短路。
第 4 步:从 4 开始,继续更新dist[]数组:4 与 1 不邻接,不更新。在dist[]中找到最小值,其顶点为 1,即此时又找到 0 到 1 的最短路。
第 5 步:所有点都已找到,停止。
对于上述步骤,你可能存在以下的疑问:
若 A 作为源点,与其邻接的只有 B,C,D 三点,其dist[]最小时顶点为 C,即就可以确定A→C为 A 到 C 的最短路。但是我们存在疑问的是:是否还存在另一条路径使 A 到 C 的距离更小? 用反证法证明。
假设存在如上图的红色虚线路径,使A→D→C的距离更小,那么A→D作为A→D→C的子路径,其距离也比A→C小,这与前面所述 “dist[]最小时顶点为 C” 矛盾,故假设不成立。因此这个疑问不存在。
根据上面的证明,我们可以推断出,Dijkstra 每次循环都可以确定一个顶点的最短路径,故程序需要循环 n-1 次。
给你们说一下博主刚开始的问题:我做题时一直将最短路径数组置为0,结果他的值本来就是最小值,是所以输出也就是0.希望大家不要犯 博主的毛病。
不说了直接上题:其实迪杰斯特拉就是不停找最短距离的过程
输入
输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。
以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
输出
只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。
请注意行尾输出换行。
样例输入
4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
样例输出
6 4 7
完整代码展示
#include
using namespace std;
#define inf 10000
#define MAXSIZE 51
int Vis[MAXSIZE];
int map[MAXSIZE][MAXSIZE];
int Dis[MAXSIZE];
void Dijkstra(int n,int start){
Vis[start]=1;
for(int i=0;imap[index][i]+Dis[index]){
Dis[i]=map[index][i]+Dis[index];
}
}
}
}
int main(int argc, char const *argv[]) {
int n,start;
cin>>n>>start;
for(int i=0;i>map[i][j];
}
}
Dijkstra(n,start);
for(int i=0;i
输出结果展示
适用范围:1、单源最短路径(从源点到其他所有点v);
2、有向图&无向图;
3、边权可正可负
4、差分约束系统
图G(v,e),源点s,数组Distant[i]记录了从源点s到顶点i的路径长度,循环执行至多n-1次,n为顶点数。
对每一条边e(u,v),如果Distant[u]+w[u,v]小于Distant[v],则Distant[v] = Distant[u]+w(u,v);
每一次循环都会至少更新一个点,所以才会出现至多循环n-1次,一次更新是指用所有节点进行一次松弛操作,(为什么会出现循环一次都能至少确定一个节点的最短距离?)
因为:1、将所有节点分为两类:已知最短距离的节点和剩余节点。
2、这两类节点满足这样的性质:已知最短距离的节点的最短距离值都比剩余节点的最短路值小。
3、易知到剩余节点的路径一定会经过已知节点。
4、而从已知节点连到剩余节点的所以边中的最小的那个边,这条边所更新后的剩余节点就一定是确定的最短距离,从而多找到了一个能确定最短距离的节点(不用知道它是哪个节点)。
实现过程的三步:1、初始化所有的点,每一个点保存一个值,表示源点到这个点的距离其他点的值设为无穷大。
2、进行循环,从1到n-1,进行松弛计算。
3、遍历所有边,如果的d[v]大于d[u]+w(u,v)存在,则有从源点可达的权为负的回路。
做题:在带权有向图G中,求G中的任意一对顶点间的最短路径问题,也是十分常见的一种问题。
解决这个问题的一个方法是执行n次迪杰斯特拉算法,这样就可以求出每一对顶点间的最短路径,执行的时间复杂度为O(n3)。
而另一种算法是由弗洛伊德提出的,时间复杂度同样是O(n3),但算法的形式简单很多。zuotiaa
算法描述
上题
输入
输入的第一行包含1个正整数n,表示图中共有n个顶点。其中n不超过50。
以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
输出
共有n行,每行有n个整数,表示源点至每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。对于某个顶点到其本身的最短路径长度,输出0。
请在每个整数后输出一个空格,并请注意行尾输出换行。
样例输入
4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
样例输出
0 3 2 1
6 0 4 7
2 5 0 3
3 6 1 0
代码展示
#include
using namespace std;
#define MAXSIZE 51
#define inf 10000
//定义两个数组
int D[MAXSIZE][MAXSIZE];//最短路径
int P[MAXSIZE][MAXSIZE];//最短路径上的转折点
void Floyd(int d[MAXSIZE][MAXSIZE],int n){
int v,w,k;
for(v=0;vD[v][k]+D[k][w]){
D[v][w]=D[v][k]+D[k][w];//更新功能
P[v][w]=P[v][k];
}
}
}
}
}
int main(int argc, char const *argv[]) {
int n;
cin>>n;
int d[MAXSIZE][MAXSIZE];
for(int i=0;i>d[i][j];
}
}
Floyd(d,n);
for(int i=0;i
结果展示
博主文章写的简单,希望大家不要嫌弃。。。。。。。。。。。