最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。 算法具体的形式包括:
确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。
确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。
全局最短路径问题 - 求图中所有的最短路径。
最短路径的几大常用的经典算法有:floyd算法、Dijkstra、spfa算法等。其中,floyd是最易于理解的算法,当然,其时间复杂度也是蛮尴尬的O(n^3)
首先说明一下:Floyd算法又称为插点法,对于每一对顶点i和j,看看是否存在一个顶点k使得从 i到k再到 j比已知的路径更短。如果是更新它。
把图用邻接矩阵G表示出来,如果从Vi到Vj有路可达,则G[i,j]=d,d表示该路的长度;否则G[i,j]=无穷大。定义一个矩阵D用来记录所插入点的信息,D[i,j]表示从Vi到Vj需要经过的点,初始化D[i,j]=j。把各个顶点插入图中,比较插点后的距离与原来的距离,G[i,j] = min( G[i,j], G[i,k]+G[k,j] ),如果G[i,j]的值变小,则D[i,j]=k。在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。
比如,要寻找从V5到V1的路径。根据D,假如D(5,1)=3则说明从V5到V1经过V3,路径为{V5,V3,V1},如果D(5,3)=3,说明V5与V3直接相连,如果D(3,1)=1,说明V3与V1直接相连。
所以说,其方法就是枚举暴力,我们可以傻瓜式的写出三个for循环就可以搞定了
//存在一个k 使aik+akj路径小于aij
for(k=0;k<C_nPointId;k++)
for(i=0;i<C_nPointId;i++)
for(j=0;j<C_nPointId;j++)
V_nMapValue[i][j]=fmin(V_nMapValue[i][j],V_nMapValue[i][k]+V_nMapValue[k][j]);
看一道例题
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2112
题目描述:
经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强。这时候,XHD夫妇也退居了二线,并在风景秀美的诸暨市浬浦镇陶姚村买了个房子,开始安度晚年了。
这样住了一段时间,徐总对当地的交通还是不太了解。有时很郁闷,想去一个地方又不知道应该乘什么公交车,在什么地方转车,在什么地方下车(其实徐总自己有车,却一定要与民同乐,这就是徐总的性格)。
徐总经常会问蹩脚的英文问路:“Can you help me?”。看着他那迷茫而又无助的眼神,热心的你能帮帮他吗?
请帮助他用最短的时间到达目的地(假设每一路公交车都只在起点站和终点站停,而且随时都会开)。
Input
输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
第二行有徐总的所在地start,他的目的地end;
接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。
note:一组数据中地名数不会超过150个。
如果N==-1,表示输入结束。
Output
如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。
Sample Input
6
xiasha westlake
xiasha station 60
xiasha ShoppingCenterofHangZhou 30
station westlake 20
ShoppingCenterofHangZhou supermarket 10
xiasha supermarket 50
supermarket westlake 10
-1
Sample Output
50
Hint:
The best route is:
xiasha->ShoppingCenterofHangZhou->supermarket->westlake
解题思路:首先,先把每个name转换成一个对应的id(由于比较懒,映射方法就直接写了一层循环遍历了= =!)
然后运用floyd枚举所有的点。
#include<stdio.h>#include<string.h>#define INF 999999999int V_nMapValue[155][155];int C_nPointId;char N_sPointName[155][40];int fmin(int a,int b) { return a<b?a:b;}void Init(){ int i,j;for(i=0;i<155;i++)for(j=0;j<155;j++)V_nMapValue[i][j]=(i==j)?0:INF;}int Get_PointId_by_PointName(char *s){int i;for(i=0;i<C_nPointId;i++)if(!strcmp(N_sPointName[i], s))return i;strcpy(N_sPointName[C_nPointId],s);C_nPointId++;return C_nPointId-1;}void Floyd(){ int i,j,k; //存在一个k 使aik+akj路径小于aij for(k=0;k<C_nPointId;k++) for(i=0;i<C_nPointId;i++) for(j=0;j<C_nPointId;j++) V_nMapValue[i][j]=fmin(V_nMapValue[i][j],V_nMapValue[i][k]+V_nMapValue[k][j]); }int main(){int n,i,j;while(~scanf("%d",&n)&&n!=-1){Init();char N_sStPoint[40], N_sEnPoint[40]; scanf("%s%s",&N_sStPoint, &N_sEnPoint);strcpy(N_sPointName[0], N_sStPoint);strcpy(N_sPointName[1], N_sEnPoint);C_nPointId = 2; char Point_a_name[40],Point_b_name[40];int Point_a_id,Point_b_id,Value_By_ab;for(i=0;i<n;i++){scanf("%s%s%d",&Point_a_name,&Point_b_name,&Value_By_ab);Point_a_id = Get_PointId_by_PointName(Point_a_name);Point_b_id = Get_PointId_by_PointName(Point_b_name);V_nMapValue[Point_a_id][Point_b_id] = V_nMapValue[Point_b_id][Point_a_id] = Value_By_ab;}if(!strcmp(N_sStPoint, N_sEnPoint)){printf("0\n");continue;}/* for(i=0;i<C_nPointId;i++) for(j=0;j<C_nPointId;j++) printf("%d%c",V_nMapValue[i][j],j==C_nPointId-1?'\n':' '); */Floyd();if(V_nMapValue[0][1]==INF)printf("-1\n");elseprintf("%d\n",V_nMapValue[0][1]);}return 0;}