现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
3 3 0 1 1 0 2 3 1 2 1 0 2 3 1 0 1 1 1 2
2 -1经典的最短路径问题:下面是我自己写的Floyd算法:#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define inf 9999999 int map[1100][1100]; int main() { int n,m; while(~scanf("%d %d",&n,&m)) { int i,j,k; //memset(map,0,sizeof(map)); for(i=0;i<n;i++) for(j=0;j<n;j++) map[i][j]=inf; int a,b,c; for(i=0;i<m;i++) { scanf("%d %d %d",&a,&b,&c); if(map[a][b]>c)//这一步好像不能少啊!! map[b][a]=map[a][b]=c; } int s,p; scanf("%d %d",&s,&p); for(k=0;k<n;k++) { for(i=0;i<n;i++) for(j=0;j<n;j++) map[i][j]=min(map[i][j],map[i][k]+map[k][j]); } if(s==p) printf("0\n"); else if(map[s][p]==inf) printf("-1\n"); else printf("%d\n",map[s][p]); } return 0; }#include<stdio.h> #include<string.h> #define M 10000000 int map[202][202]; int vis[202],dist[202]; int n,s,t; void dijkstra() { int min,i,j,k; memset(vis,0,sizeof(vis)); for(i=0; i<n; i++) dist[i]=map[s][i]; dist[s]=0; for(i=0; i<n; i++) { min=M; for(j=0; j<n; j++) if(!vis[j]&&dist[j]<min) { min=dist[j]; k=j; } if(min==M)break; vis[k]=1; for(j=0; j<n; j++) if(!vis[j]&&dist[j]>dist[k]+map[j][k]) dist[j]=dist[k]+map[j][k]; } if(dist[t]==M) printf("-1\n"); else printf("%d\n",dist[t]); } int main() { int i,j,x,y,z,m; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0; i<n; i++) for(j=0; j<n; j++) map[i][j]=M; for(i=0; i<m; i++) { scanf("%d%d%d",&x,&y,&z); if(map[x][y]>z) { map[y][x]=z; map[x][y]=z; } } scanf("%d%d",&s,&t); dijkstra(); } return 0; }
Dijkstra算法:
基本思想:设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,对vi∈V-S,假设从源点v到vi的有向边为最短路径。以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。重复上述过程,直到集合V中全部顶点加入到集合S中。
下一条最短路径(设其终点为vi)或者是弧(v0,vi),或者是中间经过S中的顶点而最后到达顶点vi的路径。
示例:
算法步骤:
① 令S={Vs} ,用带权的邻接矩阵表示有向图,对图中每个顶点Vi按以下原则置初值:
② 选择一个顶点Vj ,使得:dist[j]=Min{ dist[k]| Vk∈V-S },Vj就是求得的下一条最短路径终点,将Vj 并入到S中,即S=S∪{Vj} 。
③ 对V-S中的每个顶点Vk ,修改dist[k],方法是:
若dist[j]+Wjk<dist[k],则修改为:dist[k]=dist[j]+Wjk ("Vk∈V-S )
④ 重复②,③,直到S=V为止。
算法实现:
二、每一对顶点之间的最短路径
问题描述:给定带权有向图G=(V, E),对任意顶点vi,vj∈V(i≠j),求顶点vi到顶点vj的最短路径。
解决办法1:每次以一个顶点为源点,调用Dijkstra算法n次。显然,时间复杂度为O(n3)。
解决办法2:弗洛伊德提出的求每一对顶点之间的最短路径算法——Floyd算法,其时间复杂度也是O(n3),但形式上要简单些。
Floyd算法:
基本思想:对于从vi到vj的弧,进行n次试探:首先考虑路径vi,v0,vj是否存在,如果存在,则比较vi,vj和vi,v0,vj的路径长度,取较短者为从vi到vj的中间顶点的序号不大于0的最短路径。在路径上再增加一个顶点v1,依此类推,在经过n次比较后,最后求得的必是从顶点vi到顶点vj的最短路径。
示例:
数据结构:
图的存储结构:带权的邻接矩阵存储结构
数组dist[n][n]:存放在迭代过程中求得的最短路径长度。迭代公式:
数组path[n][n]:存放从vi到vj的最短路径,初始为path[i][j]="vivj"。