最短路
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 81686 Accepted Submission(s): 35376
输入保证至少存在1条商店到赛场的路线。
Statistic | Submit | Discuss | Note
参考网址:::https://blog.csdn.net/u012469987/article/details/51319574
Dijkstra
通俗翻译为迪杰斯特拉算法
- 适用范围:无负权回路,边权必须非负,单源最短路
- 时间复杂度:优化前O(n2
)
简单粗暴的原理
更新:2018-02-21
求t 点到s点的距离,假设距离s点最近的点p1距离为L,那么这个点一定是最短的,因为不可能有比直达最近的点还近的路,那么选它没错。
然后把s和点p1看成一个点S’,再同理选距离S’最近的点(其实这里实际求的是距离最开始的源点s),就这样一直重复操作贪心下去即可。
其中在选了p1之后我们要更新所有p1点相邻点到s点的最短距离,因为选p1点那么可能经过p1点到s点比原本的点直接到s点更近。
注意求点距离的时候求的是距离源点s最近,不是距离集合S’最近,距离集合S’最近就是最小生成树Prim算法了。
过程
数组dis[u]表示u到s点的最短距离。
我们一直找点u = min{ dis[k] , k点未访问 },这个点就是最短路上的点,然后根据其他点v跟u点的关系去更新下dis[v],不断重复找和更新即可。
dis[s]=0将源点加入最短路,然后循环n-1次每次找出一个最短路上的点,找的方法是直接找出剩下的点中dis[ ]最小的那个点u,u点就是最短路上的点,然后看看其他点v到s点的距离会不会因为这个u点的加入而改变,即若dis[v] > dis[u] + distance[u][v] 则更新dis[v]为 dis[u] + distance[u][v]。
在最开始时,只有起点s的最短距离是确定的,而在尚未标记过的定点中,距离dis[i]最小的顶点就时最短距离已经确定的顶点,由于不存在负边,所以dis[i]不会在之后的更新中变小
for(int k=1;k<=n;k++) //不断更新相邻的点 { if(vis[k]==0 && dis[k]>dis[u]+mp[u][k]) dis[k]=dis[u]+mp[u][k]; }
根据题意,先从1出发集合T{1},找距离1点最近的点,这个点是4,将4加入集合T{1,4},再找其他的2 3 5 未被标记的点,例如(从4点到2点的距离大于从1直接到2的距离,所以dis[2]中的距离不用更新;从4点到3点的距离小于从1点直接到3点的距离那么就更新dis[3]中的距离,把距离换成1-4-3的距离,即2+9=11;从4点到5点的距离为(1-4-5 2+3=5)小于从1直接到5的距离,所以更新dis[5]中的距离为(2+3=5),这样就将其他的临界点都更新了一遍,然后再执行一次循环,找其他的除了1和4的其他的点,所有的点都找一遍,都更新一遍之后,dis中存放的就是最小的距离,我们要找的是从1到n的距离,所以直接输出dis[n]就可以了)
#include<stdio.h> #include<iostream> #include<algorithm> #include<stdlib.h> #include<string.h> using namespace std; #define INF 0x3f3f3f3f #define maxn 10001 int dis[maxn]; int mp[105][105]; int vis[maxn]; int n,m; int Dijkstra(int s, int t) { for(int i=1;i<=n;i++) { dis[i]=mp[s][i]; //dis[i]中存放的是从起始点s到其他各点的距离 } dis[s]=0; //将起始点的距离标记为0 vis[s]=1; //将起始点标记 for(int i=1;i<n;i++) //寻找除了s点外的其他n-1个点 { int u,t=INF; for(int j=1;j<=n;j++) //找最小的dis[] { if(vis[j]==0 && t>dis[j] ) { u=j; t=dis[j]; } } vis[u]=1; //标记找到的最短距离的点 for(int k=1;k<=n;k++) //不断更新相邻的点 { if(vis[k]==0 && dis[k]>dis[u]+mp[u][k]) dis[k]=dis[u]+mp[u][k]; } } return dis[t]; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { int a,b,c; memset(mp,INF,sizeof(mp)); memset(vis,0,sizeof(vis)); if(n==0 || m==0) break; for(int i=1;i<=n;i++) { mp[i][i]=0; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); mp[a][b]=c; mp[b][a]=c; } int res=Dijkstra(1,n); cout<<res<<endl; } }