有这样一类题,它要求你从某个点出发,到某个为止走过的最短路径。
上一次,我们学习了弗洛伊德算法,这次,我们来看看dijkstra算法。
从起点出发,有很多条路可以走,走哪一条路最短呢?
枚举出来看一看吧。依次枚举每条边。走最短的那一条路,最后到达终点时就一定最短啦!~\(≧▽≦)/~
但是这种做法有瑕疵:不能处理负权边,负权回路,O(n²)的代码只适合单源点,即只有出发点到目标点的距离,不像弗洛伊德可以处理任意两点的距离。
这种算法的时间复杂度为O(n²),改一改改成多源点就是O(n³)了。
详见代码:
//dis[i][j]:从i点到j点的距离,
//ans[i]:i点到源点的距离,
//bobo[i]:i点有没有走过
for(int i=1;i<=n;i++) ans[i]=dis[i][begin];
bobo[begin]=true; ans[begin]=0;//标记一下
for(int i=1;i<=n;i++)
{
mini=VeryBig;
int p=-1;//以此点出发,最短的路径的点的下表
for(int j=1;j<=n;j++)
if(!bobo[j] && ans[j]<mini)
mini=ans[j],p=j;//若没有访问过且此点是最短路径,标记一下
if(p<0) break;
bobo[p]=true;//标记一下
for(int j=1;j<=n;j++)
ans[j]=min(dis[p][j]+ans[p],ans[j]);//尝试改变以此点出发的边的另一个端点的的值
}
//dis[i][j]:从i点到j点的距离,
//ans[i][j]:i点到j点的最短距离,
//bobo[i]:i点有没有走过
for(int t=1;t<=n;t++)
{
memset(bobo,0,sizeof bobo);
for(int i=1;i<=n;i++) ans[t][i]=dis[i][begin];
bobo[begin]=true; ans[t][begin]=0;//标记一下
for(int i=1;i<=n;i++)
{
mini=VeryBig;
int p=-1;//以此点出发,最短的路径的点的下表
for(int j=1;j<=n;j++)
if(!bobo[j] && ans[t][j]<mini)
mini=ans[t][j],p=j;//若没有访问过且此点是最短路径,标记一下
if(p<0) break;
bobo[p]=true;//标记一下
for(int j=1;j<=n;j++)
ans[t][j]=min(dis[p][j]+ans[t][p],ans[t][j]);//尝试改变以此点出发的边的另一个端点的的值
}
}
再来做一道例题吧!
题目描述
平面上有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位小数样例输入
50 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
样例输出
3.41详见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<functional>
using namespace std;
const int VeryBig=9999999;
struct Epic
{
int x,y;
}point[111];
double dis[111][111],ans[111];
int n,m,begin,end,a,b,bobo[111],mini;
void in()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&point[i].x,&point[i].y);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=ans[i]=VeryBig;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
dis[a][b]=dis[b][a]=sqrt(double((point[a].x-point[b].x)*(point[a].x-point[b].x)+(point[a].y-point[b].y)*(point[a].y-point[b].y)));
}
scanf("%d %d",&begin,&end);
}
void search()
{
for(int i=1;i<=n;i++) ans[i]=dis[i][begin];
bobo[begin]=true; ans[begin]=1;
for(int i=1;i<=n;i++)
{
mini=VeryBig;
int p=-1;
for(int j=1;j<=n;j++)
if(!bobo[j] && ans[j]<mini)
mini=ans[j],p=j;
if(p<0) break;
bobo[p]=true;
for(int j=1;j<=n;j++)
ans[j]=min(dis[p][j]+ans[p],ans[j]);
}
}
int main()
{
/*freopen("dijkstra.in","r",stdin);
freopen("dijkstra.out","w",stdout);*/
in();
search();
printf("%.2lf",ans[end]);
return 0;
}