Date:2019-06-18 14:14:31
单源最短路径
Dijskra算法
伪码描述
1 //G为图,全局变量;数组d为源点到达各个点的最短路径长度;s为初始顶点
2 Dijskra (G, d[], s)
3 {
4 初始化;
5 for(i<=n)
6 {
7 u = 使d[u]最小的还未被访问的定点的编号
8 vis[u] = 1;
9 for(从u出发能到达的所有顶点v)
10 {
11 if(vis[v]==0 && 以u为中介点使得s到v的距离比d[v]更近)
12 优化d[v];
13 令v的前驱pre[v]=u来记录最短路径
14 }
15 }
16 }
邻接矩阵实现
1 const int M = 1e3, INF=1x3fffffff;
2 int n, grap[M][M], vis[M]={0}, d[M];
3
4 void Dijskra(int s) //s为起点
5 {
6 fill(d, d+M, INF); //数组整体赋值
7 fill(vis, vis+M, 0);
8 d[s] = 0; //s到自身为0
9 for(int i=1; i<=n; i++)
10 {
11 int u=0, Min=INF;
12 for(int j=1; j<=n; j++) //寻找未访问的结点中最小的结点u
13 if(vis[j]==0 && d[j]<Min)
14 { //第一次执行该循环后,u = s;
15 u = j;
16 Min = d[j];
17 }
18 if(u == 0) return ; //图不连通
19 vis[u] = 1;
20 for(int v=1; v<=n; v++)
21 {
22 if(vis[v]==0 && grap[u][v]!=INF && d[u]+grap[u][v]<d[v])
23 d[v] = d[u] + grap[u][v];
24 }
25 }
26 }
邻接表实现
1 struct node
2 {
3 int v, w;
4 };
5
6 vector<node> adj[M];
7 int d[M], vis[M], n;
8
9 void Dijskra(int s)
10 {
11 fill(d, d+M, INF);
12 fill(vis,vis+M,0);
13 d[s] = 0;
14 for(int i=1; i<=n; i++)
15 {
16 int u=0, Min=INF;
17 for(int j=1; j<=n; j++)
18 if(vis[j]==0 && d[j]<Min)
19 {
20 u = j;
21 Min = d[j];
22 }
23 if(u == 0) return;
24 vis[u] = 1;
25 for(int j=1; j<=n; j++)
26 {
27 int v = adj[u][j].v;
28 if(vis[v]==0 && d[u]+adj[u][j].w<d[v])
29 d[v] = d[u]+adj[u][j].w;
30 }
31 }
32 }
多条最短路径求解第二尺度最优路径
1 //Q1: 求代价最小的最短路径
2 int cost[M][M]; //cost[u][v]表示u到v的代价
3 int c[M] //c[u]表示s到u的最少代价
4
5 fill(c,c+M,INF);
6 c[s]=0;
7 for(int v=1; v<=n; v++)
8 {
9 if(vis[v]==0 && grap[u][v]!=INF)
10 {
11 if(d[u]+grap[u][v]<d[v])
12 {
13 d[v] = d[u] + grap[u][v];
14 c[c] = c[u] + cost[u][v];
15 }
16 else if(d[u]+grap[u][v]==d[v] && c[u]+cost[u][v]<c[v])
17 c[v] = c[u] + cost[u][v];
18 }
19 }
20
21 //Q2:求点权最大的最短路径
22 int weight[M];
23 int w[M];
24
25 fill(w,w+M, 0);
26 w[s]=weight[s];
27 for(int v=1; v<=n; v++)
28 {
29 if(vis[v]==0 && grap[u][v]!=INF)
30 {
31 if(d[u]+grap[u][v] < d[v])
32 {
33 d[v] = d[u] + grap[u][v];
34 w[v] = w[u] + weight[v];
35 }
36 else if(d[u]+grap[u][v]==d[v] && w[u]+weight[v]>w[v])
37 w[v] = w[u] + weight[v];
38 }
39 }
40
41 //Q3:求最短路径的条数
42 int num[M];
43
44 fill(num, num+M, 0);
45 num[s] = 1;
46 for(int v=1; v<=n; v++)
47 {
48 if(d[u]+grap[u][v] < d[v])
49 {
50 d[v] = d[u] + grap[u][v];
51 num[v] = num[u];
52 }
53 else if(d[u]+grap[u][v]==d[v])
54 num[v] += num[u];
55 }
算法实现
1 /*
2 Sample Input:
3 //v, e, s
4 6 8 0
5 0 1 1
6 0 3 4
7 0 4 4
8 1 3 2
9 2 5 1
10 3 2 2
11 3 4 3
12 4 5 3
13 Sample Output:
14 0 1 5 3 4 6
15 */
16
17 #include<cstdio>
18 #include<algorithm>
19 using namespace std;
20 const int M=1e3, INF=1e9;
21 int n,m,s,grap[M][M],vis[M],d[M],path[M];
22
23 void Dijskra(int s)
24 {
25 fill(d, d+M, INF);
26 fill(vis,vis+M,0);
27 for(int i=0; i<n; i++)
28 path[i] = i;
29 d[s]=0;
30 for(int i=0; i<n; i++)
31 {
32 int u=-1, Min=INF;
33 for(int j=0; j<n; j++)
34 {
35 if(vis[j]==0 && d[j]<Min)
36 {
37 u = j;
38 Min = d[j];
39 }
40 }
41 if(u==-1) return;
42 vis[u] = 1;
43 for(int v=0; v<n; v++)
44 {
45 if(vis[v]==0 && grap[u][v]!=INF && d[u]+grap[u][v]<d[v])
46 {
47 d[v] = d[u] + grap[u][v];
48 path[v] = u;
49 }
50 }
51 }
52 }
53
54 void DFS(int s, int v) //输出最短路径
55 {
56 if(s == v)
57 {
58 printf("%d ", s);
59 return;
60 }
61 DFS(s,path[v]);
62 printf("%d ", v);
63 }
64
65 int main()
66 {
67 #ifdef ONLINE_JUDGE
68 #else
69 freopen("Test.txt", "r", stdin);
70 #endif
71
72 scanf("%d%d%d", &n,&m,&s);
73 fill(grap[0], grap[0]+M*M, INF);
74
75 int u,v,w;
76 for(int i=0; i<m; i++)
77 {
78 scanf("%d%d%d", &u,&v,&w);
79 grap[u][v]=w;
80 grap[v][u]=w;
81 }
82 Dijskra(s);
83 //输出最短距离
84 for(int i=0; i<n; i++)
85 printf("%d ", d[i]);
86 printf("\n");
87 //输出最短路径
88 DFS(s,5);
89 printf("\n");
90
91 return 0;
92 }
Dijskra算法+DFS
1 //Dijskra:记录所有的最短路径
2 vector<int> pre[M];
3
4 void Dijskra(int s)
5 {
6 fill(d,d+M,INF);
7 d[s] = 0;
8 for(int i=0; i<n; i++)
9 {
10 int u=-1, Min=INF;
11 for(int j=0; j<n; j++)
12 if(vis[j]==0 && d[j]<Min)
13 {
14 u = j;
15 Min = d[j];
16 }
17 if(u == -1) return;
18 vis[u] = 1;
19 for(int v=0; v<n; v++)
20 {
21 if(vis[v]==0 && grap[u][v]!=INF)
22 {
23 if(d[u]+grap[u][v] < d[v])
24 {
25 d[v] = d[u] + grap[u][v];
26 pre[v].clear();
27 pre[v].push_back(u);
28 }
29 else if(d[u]+grap[u][v] == d[v])
30 pre[v].push_back(u);
31 }
32 }
33 }
34 }
35
36 //DFS:从所有的最短路径中找出第二标尺最优的路径
37 int optValue=0,cnt=0; //最优值
38 vector<int> pre, optPath, tempPath; //path为逆序,即v->s
39
40 void DFS(int v)
41 {
42 if(v == s) //s为pre递归树的叶子结点,也即图的起点
43 {
44 tempPath.push_back(s);
45
46 int value=0;
47 //计算边权之和
48 for(int i=tempPath.size()-1; i>0; i--)
49 {
50 int id = tempPath[i]; idNext=tempPath[i-1];
51 value += v[id][idNext];
52 }
53 //计算点权之和
54 for(int i=tempPath.size()-1; i>=0; i--)
55 {
56 int id = tempPath[i];
57 value += w[id];
58 }
59 //计算路径条数
60 cnt++;
61
62 //选择最优路径
63 if(value > optValue)
64 {
65 optValue = value;
66 optPath = tempPath;
67 }
68 tempPath.pop_back();
69 return ;
70 }
71
72 tempPath.push_back(v);
73 for(int i=0; i<pre[v].size(); i++)
74 DFS(pre[v][i]);
75 tempPath.pop_back();
76 }
Bellman-Ford算法
邻接表实现
1 //邻接表法
2 int n,d[M],w[M][M];
3 vector<int> grap[M];
4
5 //判断有无负环并且给出最短路径
6 bool Bellman(int s)
7 {
8 fill(d,d+M,INF);
9 d[s] = 0;
10 for(int i=0; i<n-1; i++)
11 {
12 for(int u=0; u<n; u++)
13 {
14 for(int j=0; j<grap[u].size(); j++)
15 {
16 int v = grap[u][j];
17 if(d[u]+w[u][v] < d[v])
18 d[v] = d[u] + w[u][v];
19 }
20 }
21 }
22
23 //判断负环
24 for(int u=0; u<n; u++)
25 {
26 for(int j=0; j<grap[u].size(); j++)
27 {
28 int v = grap[u][j];
29 if(d[u]+w[u][v] < d[v])
30 return false;
31 }
32 }
33 return true;
34 }
算法实现
1 /*
2 Sample Input:
3 5 6 0 2
4 1 2 1 5 3
5 0 1 1
6 0 2 2
7 0 3 1
8 1 2 1
9 2 4 1
10 3 4 1
11 Sample Output:
12 2 4
13 */
14
15 #include<cstdio>
16 #include<cstring>
17 #include<vector>
18 #include<set>
19 #include<algorithm>
20 using namespace std;
21 const int M=1e3,INF=1e9;
22 struct node
23 {
24 int v, dis;
25 node(int _v, int _dis) : v(_v), dis(_dis) {}
26 };
27 vector<node> adj[M];
28 int n,weight[M];
29 int d[M],w[M],t[M];
30 set<int> pre[M];
31
32 void Bellman(int s)
33 {
34 fill(d, d+M, INF);
35 fill(t, t+M, 0);
36 fill(w, w+M, 0);
37 d[s] = 0;
38 w[s] = weight[s];
39 t[s] = 1;
40 for(int i=0; i<n-1; i++)
41 {
42 bool isLoose = true;
43 for(int u=0; u<n; u++)
44 {
45 for(int j=0; j<adj[u].size(); j++)
46 {
47 int v = adj[u][j].v;
48 int dis = adj[u][j].dis;
49 if(d[u]+dis < d[v])
50 {
51 d[v] = d[u] + dis;
52 w[v] = w[u] + weight[v];
53 t[v] = t[u];
54 pre[v].clear();
55 pre[v].insert(u);
56 isLoose = false;
57 }
58 else if(d[u]+dis == d[v])
59 {
60 if(w[u]+weight[v] > w[v])
61 w[v] = w[u] + weight[v];
62 pre[v].insert(u); //BF算法会多次访问同一个结点,使用set可以去重
63 t[v]=0;
64 set<int>::iterator it;
65 for(it=pre[v].begin(); it!=pre[v].end(); it++)
66 t[v] += t[*it]; //重新计算最短路径条数
67 }
68 }
69 }
70 if(isLoose)
71 break; //不再松弛时退出
72 }
73 }
74
75 int main()
76 {
77 #ifdef ONLINE
78 #else
79 freopen("Test.txt", "r", stdin);
80 #endif // ONLINE
81
82 int m,s,v;
83 scanf("%d%d%d%d", &n,&m,&s,&v);
84 for(int i=0; i<n; i++)
85 scanf("%d", &weight[i]);
86 int v1,v2,c;
87 for(int i=0; i<m; i++)
88 {
89 scanf("%d%d%d", &v1,&v2,&c);
90 adj[v1].push_back(node(v2,c));
91 adj[v2].push_back(node(v1,c));
92 }
93 Bellman(s);
94 printf("%d %d\n", t[v], w[v]);
95
96 return 0;
97 }
全源最短路径
Floyd算法
算法实现
1 /*
2 6 8
3 0 1 1
4 0 3 4
5 0 4 4
6 1 3 2
7 2 5 1
8 3 2 2
9 3 4 3
10 4 5 3
11 */
12 #include<cstdio>
13 #include<algorithm>
14 using namespace std;
15 const int M=220,INF=1e9;
16 int n,m,dis[M][M];
17
18 void Floyd()
19 {
20 for(int k=0; k<n; k++)
21 for(int i=0; i<n; i++)
22 for(int j=0; j<n; j++)
23 if(dis[i][k]!=INF && dis[k][j]!=INF && dis[i][k]+dis[k][j]<dis[i][j])
24 dis[i][j] = dis[i][k] + dis[k][j];
25 }
26
27 int main()
28 {
29 freopen("Test.txt", "r", stdin);
30
31 int u,v,w;
32 fill(dis[0],dis[0]+M*M,INF);
33 scanf("%d%d", &n,&m);
34 for(int i=0; i<n; i++)
35 dis[i][i]=0;
36 for(int i=0; i<m; i++)
37 {
38 scanf("%d%d%d",&u,&v,&w);
39 dis[u][v] = w;
40 }
41 Floyd();
42 for(int i=0; i<n; i++)
43 {
44 for(int j=0; j<n; j++)
45 printf("%d ", dis[i][j]);
46 printf("\n");
47 }
48
49 return 0;
50 }