关于这两个最短路径的算法的阐述和理解,可以看本人的这篇文章,希望能给你们带来帮助:
算法学习:最短路径
一、弗洛伊德最短路径算法
题目描述
在带权有向图G中,求G中的任意一对顶点间的最短路径问题,也是十分常见的一种问题。
解决这个问题的一个方法是执行n次迪杰斯特拉算法,这样就可以求出每一对顶点间的最短路径,执行的时间复杂度为O(n3)。
而另一种算法是由弗洛伊德提出的,时间复杂度同样是O(n3),但算法的形式简单很多。
在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法求出每一对顶点间的最短路径长度。
输入
输入的第一行包含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
分析:就是弗洛伊德算法的板子题,但是题目要求的是,相同的点输入一定为0,还有没有连通的时候距离也输入0,我们只需要在主函数做处理,换成INF就好了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int INF=1e6;
const int NUM=55;
int n;
int graph[NUM][NUM];
void floyd(){
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
if(graph[i][k]!=INF)
for(int j=1;j<=n;++j)
if(graph[i][j]>graph[i][k]+graph[k][j])
graph[i][j]=graph[i][k]+graph[k][j];
for(int s=1;s<=n;++s){
for(int i=1;i<=n;++i)
if(s==i)printf("0 ");
else if(graph[s][i]!=INF)printf("%d ",graph[s][i]);
else printf("-1 ");
printf("\n");
}
}
int main(){
int len;
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;++j){
scanf("%d",&len);
if(len)graph[i][j]=len;
else graph[i][j]=INF;
}
floyd();
}
2、迪杰斯特拉最短路径算法
题目描述
在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。
在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。
在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法求出源点至每一个其它顶点的最短路径长度。
输入
输入的第一行包含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
分析:处理0和上述是一样的步骤,不过按这个样例来看,可以比较容易看出结点是从0开始算的,所以样例输入的s为1,实际上就是结点2了。注意这点就好了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int INF=1e6;
const int NUM=55;
int n;
struct edge{
int from,to,w;
edge(int a,int b,int c){from=a;to=b;w=c;}
};
vector<edge>e[NUM];
struct s_node{
int id,n_dis;
s_node(int b,int c){id=b;n_dis=c;}
bool operator<(const s_node &a)const
{return n_dis>a.n_dis;}
};
void dijkstra(int s){
int dis[NUM];
bool done[NUM];
for(int i=1;i<=n;i++)dis[i]=INF,done[i]=false;
dis[s]=0;
priority_queue<s_node>Q;
Q.push(s_node(s,dis[s]));
while(!Q.empty()){
s_node u=Q.top();
Q.pop();
if(done[u.id])true;
for(int i=0;i<e[u.id].size();++i){
edge y=e[u.id][i];
if(done[y.to])continue;
if(dis[y.to]>y.w+u.n_dis){
dis[y.to]=y.w+u.n_dis;
Q.push(s_node(y.to,dis[y.to]));
}
}
}
for(int i=1;i<=n;i++)
if(i!=s){
if(dis[i]!=INF)printf("%d ",dis[i]);
else printf("-1 ");
}
printf("\n");
}
int main(){
int len,s;
scanf("%d%d",&n,&s);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
scanf("%d",&len);
if(len)e[i].push_back(edge(i,j,len));
else e[i].push_back(edge(i,j,INF));
}
dijkstra(s+1);
}
3、单源最短路径问题
题目描述
编程实现Dijkstra算法,求一个有向加权图中,从源点出发到其他各个顶点的最短路径。
输入
第1行第1个值表示顶点个数,第2个值表示边个数;第2行开始为边(两个顶点,边的起点和终点)及权重。
输出
顶点0到每一个顶点的最短路径长度。
样例输入
5 7
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60
样例输出
0 10 50 30 60
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int INF=1e6;
const int NUM=55;
int n;
struct edge{
int from,to,w;
edge(int a,int b,int c){from=a;to=b;w=c;}
};
vector<edge>e[NUM];
struct s_node{
int id,n_dis;
s_node(int b,int c){id=b;n_dis=c;}
bool operator<(const s_node &a)const
{return n_dis>a.n_dis;}
};
void dijkstra(int s){
int dis[NUM];
bool done[NUM];
for(int i=1;i<=n;i++)dis[i]=INF,done[i]=false;
dis[s]=0;
priority_queue<s_node>Q;
Q.push(s_node(s,dis[s]));
while(!Q.empty()){
s_node u=Q.top();
Q.pop();
if(done[u.id])true;
for(int i=0;i<e[u.id].size();++i){
edge y=e[u.id][i];
if(done[y.to])continue;
if(dis[y.to]>y.w+u.n_dis){
dis[y.to]=y.w+u.n_dis;
Q.push(s_node(y.to,dis[y.to]));
}
}
}
for(int i=0;i<n;i++)
printf("%d%c",dis[i],i==n-1?'\n':' ');
}
int main(){
int len,E,x,y;
scanf("%d%d",&n,&E);
while(E--){
scanf("%d%d%d",&x,&y,&len);
e[x].push_back(edge(x,y,len));
}
dijkstra(0);
}