hyh大佬很热爱学习,他打算偷偷跑回学校学习,为了多学习他希望可以找最快的路线回到学校。
广州市里有N个(2 <= N <= 1000)个地铁站,编号分别为1..N。zzj家在1号地铁站旁边,五山站是N号地铁站。地铁站之间共有M (1 <= M <= 2000)条双向路径。
hyh现在在1号地铁站,他希望知道到学校最短要多长时间。可以保证hyh能到达学校。忽略hyh在换乘地铁时需要的等待时间
Sample Input 5 5 1 2 20 2 3 30 3 4 20 4 5 20 1 5 100 Sample Output 90
Dijkstra算法思想:主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。 时间复杂度O(n^2),代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxx = 1005; int adj[maxx][maxx]; // 邻接表来存储图的信息 bool found[maxx]; //标记是否访问过该结点 int t, n; const int inf = 1 << 29; //记住不要将最大值设成101等,虽然说题目给的边的大小是1 ~ 100 但是输入数据有坑 void init() { // 初始化 for (int i = 1; i <= n ; ++i) { for (int j = 1; j <= n; ++j) { adj[i][j] = inf; } } memset(found, false, n + 1); } void dijkstra() { int dis[n + 1]; for (int i = 1; i <= n; ++i) { dis[i] = adj[n][i]; // 首先对distance数组进行初始化 我选择的是从结点n到结点1 // 也可以选择从结点1到结点n } found[n] = true; for (int i = 1; i <= n; ++i) { int minv = 0, mind = inf; //找到在未被访问的结点之中的最小的结点 for (int j = 1; j <= n; ++j) { if (found[j]) continue; if (dis[j] < mind) { minv = j; mind = dis[j]; } } for (int j = 1; j <= n; ++j) { if (adj[minv][j] != inf) { dis[j] = min(dis[j], adj[minv][j] + dis[minv]); // 对dis进行更新 } } found[minv] = true; } printf("%d ", dis[1]); } int main() { scanf("%d%d", &t, &n); init(); for (int i = 0; i < t; ++i) { int from, to, edge; scanf("%d%d%d", &from, &to, &edge); adj[from][to] = adj[to][from] = min(adj[from][to], edge); // 去重边 } dijkstra(); return 0; }
Floyd算法思想:(时间复杂度O(N^3),在此题中会超时,写出来只是供大家学习一下)
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
#include <iostream> #include <vector> #include <algorithm> #include <cstdio> typedef long long ll; typedef unsigned long long ull; using namespace std; int t, n; const int maxx = 1005; int gra[maxx][maxx], path[maxx][maxx]; const int inf = 1 << 29; void floyd() { vector<vector<int> > A(n + 1, vector<int>(n + 1)); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { A[i][j] = gra[i][j]; path[i][j] = -1; } } for (int v = 1; v <= n; ++v) { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { if (A[i][j] > A[i][v] + A[v][j]) { A[i][j] = A[i][v] + A[v][j]; path[i][j] = v; } } } } } int printPath(int v, int w) { if (-1 == path[v][w]) { return gra[v][w]; } int mid = path[v][w]; return printPath(v, mid) + printPath(mid, w); } int main() { scanf("%d%d", &t, &n); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { if (i != j) gra[i][j] = inf; } } for (int i = 0; i < t; ++i) { int from, to, edge; scanf("%d%d%d", &from, &to, &edge); gra[from][to] = gra[to][from] = min(gra[from][to], edge); } floyd(); printf("%d ", printPath(n, 1)); return 0; }
相比较可得知Dijkstra算法更优于Floyd算法,但是,Dijkstra算法不能处理负权边而Floyd可以,一般我们可以观察题目给出的数据大小来选择我们解题的算法。