最短路问题-- Dijkstra Choose the best route
Choose the best route
Problem Description
One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are near Kiki’s home so that she can take. You may suppose Kiki can change the bus at any station. Please find out the least time Kiki needs to spend. To make it easy, if the city have n bus stations ,the stations will been expressed as an integer 1,2,3…n.
Input
There are several test cases.
Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
Output
The output contains one line for each data set : the least time Kiki needs to spend ,if it’s impossible to find such a route ,just output “-1”.
$Dijkstra$ 算法:以点为思考中心的最短路径算法。
图结构存储:邻接表
流程:1.初始化
1 const int INF = 1e9;
2 bool hasFind[maxn];
3 for (int i = 0 ;i<= n ;i++)
4 dist[i] = INF;
5 dist[sNode] = 0;
6 memset(hasFind,0,sizeof hasFind);
7 hasFind[sNode] = true;
具体流程为:
1 for (int i = 0 ;i< n-1 ;i++){
2 int nId = -1 ;
3 for (int j = 0 ;j< n ;j++){
4 if (!hasFind[j]){
5 if (nId == -1)
6 nId = j;
7 else if (dist[j]<dist[nId])
8 nId = j;
9 }
10 }
11 hasFind[nId] = true;
12 for (int i = 0 ;i< node[nId].size() ;i++){
13 int nextId = node[nId][i].nextId;
14 if (node[nId][i].dist + dist[nId]< dist[nextId]){
15 dist[nextId] = node[nId][i].dist + dist[nId];
16 que.push(nextId);
17 }
18 }
19 }
时间复杂度 节点个数 $N$,边个数 $M$ $O$($N\times N$)
举例 • 求所有节点到节点 1 的最短距离
1. 初始化
• 将源节点 1,放入已获取最短路径集合, 集合变为 {1}
• 未获取最短路径节点结合 {2,3,4,5}
• 根据节点 1 来更新所有节点距离源节点的距离 $dist$
2. 流程
(a) $step$ 1:
• 从未获取最短路径节点结合 {2,3,4,5} 中,选取距离源节点最 近的节点 3
• 将节点 3,放入已获取最短路径集合, 集合变为 {1,3}
• 根据节点 3 来更新所有节点距离源节点的距离 $dist$
(b) $step$ 2:
• 从未获取最短路径节点结合 {2,4,5} 中,选取距离源节点最 近的节点 2
• 将节点 2,放入已获取最短路径集合, 集合变为 {1,2,3}
• 根据节点 2 来更新所有节点距离源节点的距离 $dist$
(c) $step$ 3:
• 从未获取最短路径节点结合 {4,5} 中,选取距离源节点最近 的节点 4
• 将节点 4,放入已获取最短路径集合, 集合变为 {1,2,3,4}
• 根据节点 4 来更新所有节点距离源节点的距离 $dist$
(d) $step$ 4:
• 从未获取最短路径节点结合 {5} 中,选取距离源节点最近的 节点 5
• 将节点 5,放入已获取最短路径集合, 集合变为 {1,2,3,4,5}
• 根据节点 5 来更新所有节点距离源节点的距离 $dist$
(e) 终止条件,所有节点都放入到了已获取最短路径集合。
把所有部分合并在一起得到一段代码:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<iostream>
5 #define Inf 0x3f3f3f3f
6
7 using namespace std;
8 int map[1005][1005];
9 int vis[1005],dis[1005];
10 int n,m;//n个点,m条边
11 void Init ()
12 {
13 memset(map,Inf,sizeof(map));
14 for(int i=1;i<=n;i++)
15 {
16 map[i][i]=0;
17 }
18 }
19 void Getmap()
20 {
21 int u,v,w;
22 for(int t=1;t<=m;t++)
23 {
24 scanf("%d%d%d",&u,&v,&w);
25 if(map[u][v]>w)
26 {
27 map[u][v]=w;
28 map[v][u]=w;
29 }
30 }
31 }
32
33 void Dijkstra(int u)
34 {
35 memset(vis,0,sizeof(vis));
36 for(int t=1;t<=n;t++)
37 {
38 dis[t]=map[u][t];
39 }
40 vis[u]=1;
41 for(int t=1;t<n;t++)
42 {
43 int minn=Inf,temp;
44 for(int i=1;i<=n;i++)
45 {
46 if(!vis[i]&&dis[i]<minn)
47 {
48 minn=dis[i];
49 temp=i;
50 }
51 }
52 vis[temp]=1;
53 for(int i=1;i<=n;i++)
54 {
55 if(map[temp][i]+dis[temp]<dis[i])
56 {
57 dis[i]=map[temp][i]+dis[temp];
58 }
59 }
60 }
61 }
62
63 int main()
64 {
65
66 scanf("%d%d",&m,&n);
67 Init();
68 Getmap();
69 Dijkstra(n);
70 printf("%d\n",dis[1]);
71 return 0;
72 }
这道题的代码如下:
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <string>
6 #include <cmath>
7 #include <cstdlib>
8 using namespace std;
9
10 const int INF=0x3f3f3f3f;
11 const int N=1010;
12 int mp[N][N];
13 int dis[N];
14 int vis[N];
15 int m;
16 int n;
17 int dijstra()
18 {
19 memset(dis,0x3f,sizeof(dis));
20 memset(vis,0,sizeof(vis));
21 dis[0]=0;
22 for(int i=1;i<=n;i++)
23 {
24 int k=0;
25 int mini=INF;
26 for(int j=1;j<=n;j++)
27 {
28 if(!vis[j]&&mini>dis[j])
29 mini=dis[k=j];
30 }
31 vis[k]=1;
32 if(k==m) return dis[m];
33 for(int j=1;j<=n;j++)
34 {
35 if(vis[j]||mp[k][j]==INF) continue;
36 dis[j]=min(dis[j],dis[k]+mp[k][j]);
37 }
38 }
39 return dis[m];
40 }
41 int main()
42 {
43 int s; //已修好的路有几条
44 while(~scanf("%d%d%d",&n,&s,&m)) //终点是m,最远的点是n
45 {
46 memset(mp,INF,sizeof(mp));
47 while(s--)
48 {
49 int a,b,c;
50 scanf("%d%d%d",&a,&b,&c);
51 if(mp[a][b]>c)
52 mp[a][b]=c;
53 }
54 int d;
55 scanf("%d",&d);
56 while(d--)
57 {
58 int x;
59 scanf("%d",&x);
60 mp[0][x]=0;
61 }
62 int k=dijstra();
63 if(k==INF) printf("-1\n");
64 else printf("%d\n",dijstra());
65 }
66 return 0;
67 }