单源最短路径

来源:互联网 发布:天刀女神刀捏脸数据 编辑:程序博客网 时间:2024/06/06 04:35

单源最短路径问题,即在图中求出给定顶点到其他任一顶点的最短路径。

1.最短路径的最优子结构性质

该性质描述为:如果P(i, j) = {Vi ...... Vk ... Vs ... Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k, s)必定是从k到s的最短路径。

证明:假设P(i, j) = {Vi ...... Vk ... Vs ... Vj}是从顶点i到j的最短路径,则有P(i, j) = P(i, k) + P(k, s) + P(s, j)。如果P(k, s)不是从k到s的最短距离,那么必然存在另一条从k到s的最短路径P'(k, s),那么P'(i, j) = P(i, k) + P'(k, s) + P(s, j) < P(i, j)。则与P(i, j)是从i到j的最短路径相矛盾。因此该性质得证。

2.Dijkstra算法

由上述性质可知,如果存在一条从i到j的最短路径{Vi ...... Vk, Vj}, Vk是Vj前面的一个顶点。那么(Vi ... Vk)也必定是从i到k的最短路径。

为了求出最短路径,Dijkstra就提出了以最短路径长度递增,逐次生成最短路径的算法。比如对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j] = min{ dist[j], dist[i] + matrix[i][j] }。

根据这种思路:

假设存在G = <V, E>,源顶点为V0, U = {V0}, dist[i]记录V0到i的最短距离,path[i]记录从V0到i路径上的i前面的一个顶点。

(1)从V-U中选择使dist[i]值最小的顶点i,将i加入到U中;

(2)更新与i直接相邻顶点的dist值(dist[j] = min{dist[j], dist[i] + matrix[i][j})

(3)直到U=V,停止。


示例代码:

// Test.cpp : Defines the entry point for the console application.//// In Practice, You should use the statndard input/output// in order to receive a score properly.// Do not use file input and output. Please be very careful. #include <cstdio>#include <iostream>#include <stack>#define M 100#define N 100using namespace std;typedef struct node{int matrix[N][M];   //邻接矩阵int n;              //顶点数int e;              //边数}MGraph;void DijkstraPath(MGraph g, int* dist, int* path, int v0){int i, j, k;bool *visited = new bool[sizeof(bool) * g.n];for (i = 0; i < g.n; i++){if (i == v0){path[i] = v0;dist[i] = 0;visited[i] = true;continue;}if (g.matrix[v0][i] > 0){dist[i] = g.matrix[v0][i];path[i] = v0;}else{dist[i] = INT_MAX;path[i] = -1;}visited[i] = false;}for (i = 1; i < g.n; i++){int min = INT_MAX;int u;//从V-U中选择使dist[i]值最小的顶点i,将i加入到U中for (j = 0; j < g.n; j++){if (visited[j] == false && dist[j] < min){min = dist[j];u = j;}}visited[u] = true;//更新与i直接相邻顶点的dist值(dist[j] = min{dist[j], dist[i] + matrix[i][j})for (k = 0; k < g.n; k++){if (visited[k] == false && g.matrix[u][k] > 0 && min + g.matrix[u][k] < dist[k]){dist[k] = min + g.matrix[u][k];path[k] = u;}}}delete[] visited;}//打印最短路径上的各个顶点void printPath(int *path, int v, int v0)    {stack<int> s;int u = v;while (v != v0){s.push(v);v = path[v];}s.push(v);while (!s.empty()){cout << s.top() << " ";s.pop();}}int main(int argc, char** argv){int tc, T;int n, e;            //表示输入的顶点数和边数int i, j;int s, t, w;         //表示存在一条边s->t,权值为wMGraph g;int v0;              //表示源顶点// The freopen function below opens input.txt file in read only mode, and afterward,// the program will read from input.txt file instead of standard(keyboard) input.// To test your program, you may save input data in input.txt file,// and use freopen function to read from the file when using cin function.// You may remove the comment symbols(//) in the below statement and use it.// Use #include<cstdio> or #include<stdio.h> to use the function in your program.// But before submission, you must remove the freopen function or rewrite comment symbols(//).freopen("input.txt", "r", stdin);cin >> T;for (tc = 0; tc < T; tc++){/***********************************  Implement your algorithm here. ************************************/cin >> n >> e;int *dist = new int[sizeof(int) * n];int *path = new int[sizeof(int) * n];//初始化for (i = 0; i < N; i++)for (j = 0; j < M; j++)g.matrix[i][j] = 0;g.n = n;g.e = e;for (i = 0; i < e; i++){cin >> s >> t >> w;g.matrix[s][t] = w;}cin >> v0;DijkstraPath(g, dist, path, v0);for (i = 0; i < n; i++){if (i != v0){printPath(path, i, v0);cout << dist[i] << endl;}}delete[] dist;delete[] path;}return 0;//Your program should return 0 on normal termination.}


0 0
原创粉丝点击