1. 问题
最短路,顾名思义,是求出一条最短的路。具体来说,在一张图上,给定起点s和终点t,取出权值和最小的边,使得从s能到达t。
2. 解析
1、floyd算法
此算法是一种比较暴力的算法,每次枚举三个点a,b,c,如果dis(a,b)>dis(a,c)+dis(c,b),那么说明,a->b的路径中,我可以选择点c,将dis(a,b)的值更新为dis(a,c)+dis(c,b),这样的操作我们叫做松弛,就在不断枚举不断松弛中,dis(a,b)就表示a->b的最小距离。
2、dijkstra算法
①.初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
②.从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。
③.更新U中各个点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;如,(s,v)的距离可能大于(s,k)+(k,v)的距离
④.重复步骤(2)和(3),直到遍历完所有顶点。
3. 设计
1、Floyd算法
for (int i = 1; i <= n; i++) { for (int k = 1; k <= n; k++) { for (int j = 1; j <= n; j++) { p[k][j] = min(p[k][j], p[k][i] + p[i][j]);//松弛操作 } } }
2、Dijkstra算法
while(队列非空){
int a=队头的dis,b=队头的x;
for(与点b相连的边){
if(w+a<dis[to]){
dis[to]=w+a;
(dis[to],to)入队;
}
}
}
4. 分析
1、毫无疑问,floyd的时间复杂度是O(n³),这个算法有优点有缺点,缺点当然是复杂度太高,效率太慢;优点是询问方便,每次询问的复杂度为O(1)。它预处理了出所有点相互之间的最短距离。
2、Dijkstra的复杂度很容易计算,普通的复杂度为O(n²),优化点在于如何取出离集合最近的点,我采用了小根堆,可以O(1)地取出最近的点,更新操作需要O(logn),综上,堆优化后的复杂度为O(nlogn)。
5. 源码
1、Floyd
/*
author: keke
project name:Floyd算法
Time Complexity: O(n³)
*/
#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int mo[4][2] = { -1,0,1,0,0,-1,0,1 };
//int mo[8][2] = { -1,0,1,0,-1,-1,1,1,0,-1,0,1,1,-1,-1,1 };
const int maxn = 110;
ll n, m, is, t, ans, p[maxn][maxn], a, b, c;
int main() {
#ifdef ONLINE_JUDGE
#else
//freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cout << fixed << setprecision(2);
while (cin >> n >> m) {
for (int i = 1; i <= n; i++) {
for (int k = 1; k <= n; k++) {
if (i == k)p[i][k] = 0;
else p[i][k] = 1e18;
}
}
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
p[a][b] = p[b][a] = min(c, p[a][b]);//二维矩阵存图
}
for (int i = 1; i <= n; i++) {
for (int k = 1; k <= n; k++) {
for (int j = 1; j <= n; j++) {
p[k][j] = min(p[k][j], p[k][i] + p[i][j]);//松弛操作
}
}
}
cin >> a >> b;
if (p[a][b] == 1e18)cout << "No path" << "\n";
else cout << p[a][b] << "\n";
}
return 0;
//good job!
}
2、Dijkstra
/*
author: keke
project name:Dijkstra算法(堆优化)
Time Complexity: O(nlog(n))
*/
#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int mo[4][2] = { -1,0,1,0,0,-1,0,1 };
//int mo[8][2] = { -1,0,1,0,-1,-1,1,1,0,-1,0,1,1,-1,-1,1 };
const int maxn = 110;
int n, m, is, t, ans, cnt, head[maxn], a, b, c, dis[maxn];
bool vis[maxn];
struct xx {
int t, next, w;
}xx[maxn << 1];
void add(int a, int b, int c) {//链式前向星
xx[cnt].next = head[a];
xx[cnt].t = b;
xx[cnt].w = c;
head[a] = cnt++;
}
void solve(int x, int y) {
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++)dis[i] = inf;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
while (!q.empty())q.pop();
dis[x] = 0;
q.push(make_pair(0, x));//采用堆优化
while (!q.empty()) {
int a = q.top().first, b = q.top().second;
q.pop();
if (vis[b])continue;
vis[b] = true;
for (int i = head[b]; ~i; i = xx[i].next) {
int to = xx[i].t;
if (xx[i].w + a < dis[to]) {//松弛操作
dis[to] = a + xx[i].w;
q.push(make_pair(dis[to], to));
}
}
}
if (dis[y] == inf)cout << "No path" << "\n";
else cout << dis[y] << "\n";
}
int main() {
#ifdef ONLINE_JUDGE
#else
//freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cout << fixed << setprecision(2);
while (cin >> n >> m) {
cnt = 0;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
cin >> a >> b;
solve(a, b);
}
return 0;
//good job!
}