一、题目描述
最短路径问题(floyed.cpp & dijkstra.cpp)
题目描述
平面上有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位小数
样例输入
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
二、分析
1、Floyed算法O(n³)
我们先对输入的数据进行初始化:
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double dis[105][105];//dis[i][j]表示点i到点j的最短路径长度
int zb[105][2];//坐标
int main()
{
//freopen("floyed.in","r",stdin);
//freopen("floyed.out","w",stdout);
int n,m,i,j,k,x,y,q,z;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d",&zb[i][0],&zb[i][1]);
scanf("%d",&m);
memset(dis,0x7f,sizeof(dis));//清为最大值,以便后面求最短路
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
dis[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));//计算两点之间的距离
dis[y][x]=dis[x][y];
}
scanf("%d%d",&q,&z);
}</span>
floyed算法其实就是3个for循环,用i、j、k三个循环变量来枚举每一个点。用k来枚举中转点,i、j来枚举i到j的点。
如果dis[i][k]+dis[k][j]<dis[i][j],则dis[i][j]=dis[i][k]+dis[k][j]。就是 i 到 k 的距离与 k 到 j 的距离的和,小于
i 到 j 的距离,就把dis[i][j]变成 i 到 k 的距离与 k 到 j 的距离
的和。
<span style="font-size:18px;">for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j&&j!=k&&i!=k)
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);</span>
最后输出结果:<span style="font-size:18px;">printf("%.2f",dis[q][z]);</span>
2、Dijkstra算法O(n²)
还是先进行初始化:
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
double f[105][105];//用f[x][y]来存x,y的距离(但不是最短距离)
double dis[105];//存最终结果
bool b[105];//判断重复
int zb[105][2];
int main()
{
//freopen("dijkstra.in","r",stdin);
//freopen("dijkstra.out","w",stdout);
int n,m,i,j,k,x,y,q,z,xi;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d",&zb[i][0],&zb[i][1]);
scanf("%d",&m);
memset(f,0x7f,sizeof(f));
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
f[x][y]=sqrt(pow(1.0*(zb[x][0]-zb[y][0]),2)+pow(1.0*(zb[x][1]-zb[y][1]),2));
f[y][x]=f[x][y];
}
scanf("%d%d",&q,&z);
}</span>
我们可以发现dis变成了一维数组,因为Dijkstra算法是一种用来计算一个点到其他所有点的最短路径算法,Dijkstra算法是先用一个循环变量 i 来枚举所有点,把每一个枚举过的点在b数组中标记为1,然后记录下距离
点 i 最近的一个点 k ,以点 k 来进行其他最短距离的更新,
<span style="font-size:18px;">for(i=1;i<=n;i++)
dis[i]=f[q][i];
b[q]=1;
dis[q]=0;
for(i=1;i<=n-1;i++){
xi=10000000;
k=0;
for(j=1;j<=n;j++){
if(b[j]==0&&dis[j]<xi){
xi=dis[j];
k=j;
}
}
if(k==0)
break;
b[k]=1;
for(j=1;j<=n;j++)//进行更新
dis[j]=min(dis[j],dis[k]+f[k][j]);
}
printf("%.2f",dis[z]);</span>