佛洛伊德是最简单的最短路径算法,可以计算图中任意两点间的最短路径。时间复杂度为O(N3),适用于出现负边权的情况。
算法描述:
( a )初始化:点u、v如果有边相连,则dis[u][v]=w[u][v]
如果不相连,则dis[u][v]=0x3f
( b )模板:
for(k=1;k<=n;k++){
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j];
}
}
}
( c )算法结束:dis[i][j]得出的就是任意起点i到任意终点j的最短路径。
疑问:为什么枚举中间点的循环k要放在最外层?
可以从一定不经过k点与一定经过k点的三维数组比较中推导出来
Floyd算法输出路径也是采用记录前驱点的方式。因为floyd是计算任意两点间最短路径的算法,dis[i][j]记录从i到j的最短路径值。故我们定义pre[i][j]为一个二维数组,记录从i到j的最短路径中,j的前驱点是哪一个。递归还原路径。
初始化pre[N][N]为0,输入相连边时,重置相连边尾结点的前驱
若有无向边:pre[a][b]=a; pre[b][a]=b;
更新若floyd最短路有更新,那么pre[i][j]=pre[k][j];(这能不能直接赋值k的值?)
递归输出指两点s,e的最短路,先输出起点s,再将终点e放入递归,输出s+1~e的所有点。
void print(int x){
if(pre[s][x]==0) return;
print(pre[s][x]);
printf(“->%d”,x);
}
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
输入格式
第1行:1个整数n
第2…n+1行:每行2个整数x和y,描述了一个点的坐标
第n+2行:1个整数m,表示图中连线的数量
接下来有m行,每行2个整数i和j,表示第i个点和第j个点之间有连线
最后1行:2个整数s和t,分别表示源点和目标点
输出格式
第1行:1个浮点数,表示从s到t的最短路径长度,保留2位小数(如果到达不了,输出极大值0x7f对应的double类型的值)
样例
样例输入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
样例输出
3.41
这一道十分水的题,就是Floyd的板题
#include
#include
#include
#include
using namespace std;
const int M=105;
double G[M][M];
int xi[M],yi[M];
int main(){
memset(G,0x7f,sizeof(G));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&xi[i],&yi[i]);
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
int s,t;
scanf("%d %d",&s,&t);
G[s][t]=sqrt((xi[s]-xi[t])*(xi[s]-xi[t])*1.0+(yi[s]-yi[t])*(yi[s]-yi[t])*1.0)*1.0;
G[t][s]=G[s][t];
}
int s,t;
scanf("%d %d",&s,&t);
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
}
}
}
printf("%.2lf",G[s][t]);
}
小明作为一名刚学习信息学的蒟蒻(即魔芋[Talloran注]),一开始便感受到了这个领域深深的恶意.他决定每天下午外出跑步,以达到放松心情的目的.
小明生活的城市被分为n个地区,每两个地区间都可能存在一条双向联通的道路.而这些道路总共有k条.作为一名蒟蒻,他有着严重的强迫症,
因此,若两个地区间有多条直接联通道路,他会毫不犹豫地选择最长的那一条.
小明选择了作为神犇的你,帮助他求出在将来x天,从a区域到b区域的最短路径.
输入格式
第一行3个数字,分别是n,k,x.n表示小明所在城市中地区的个数,k表示地区间道路的总数,x表示小明查询的天数.
接下来k行,每行有3个数(可能为小数,不要说我没提醒你用某数据类型):c,d,e,表示从c到d直接联通的道路的长度为e
接下来x行,每行两个整数:a,b,表示小明今天查询的从a到b的最短路径(如果答案小数部分不为0,保留1位小数,否则输出整数).
输出格式
输出共x行,表示当天小明查询的最短路径
样例
输入:
5 7 3
1 2 6
2 3 10
3 4 5
4 5 4
5 1 2
2 5 8
1 4 7
1 4
1 3
3 5
输出:
6
11
9
#include
#include
#include
using namespace std;
const int M=505;
double G[M][M];
int main(){
for(int i = 0;i < M;i ++)
for(int j = 0;j < M;j ++)
G[i][j] = 0x7f7f7f7f * 1.0;
int n,m,k;
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++){
double w;
int s,t;
scanf("%d %d %lf",&s,&t,&w);
if(G[s][t] != 0x7f7f7f7f)
G[s][t]=max(G[s][t],w);
else
G[s][t]=w;
G[t][s]=G[s][t];
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(G[i][j]>G[i][k]+G[k][j]){
G[i][j]=G[i][k]+G[k][j];
}
}
}
}
for(int i=1;i<=k;i++){
int s,t;
scanf("%d %d",&s,&t);
printf("%g\n",G[s][t]);
}
return 0;
}