C++算法之——最短路径(基础1)@2020版
什么是最短路径
百度中的定义:用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
我自己的理解就是枚举得到最近的一个点,再向外进行探索直到目标点
知识的串通
你可以清晰从定义了解到这就是最基础的广度优先搜索一类的题目,一定会找到最优解。
我新学的时候也会与最小生成树这类的最短问题弄混,但他们是有实质上的不同的。请看:
最小生成树是用和最少的边集将一个图连成任意2点可达,并且这个边集的总长度最小。保证整个拓扑图的所有路径之和最小。通常用Prim算法和kruskal算法求解。
对于数据量在一定限度内时,可以选用较为简单的Kruskal算法,下面写一段基础代码:
我用了并查集进行实现
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int u, v, w;
};
Edge e[200000];
int father[200], n, en, sum, w, tot;
bool cmp(Edge a, Edge b) {
return a.w < b.w;
}
int find(int x) {
if (x == father[x])
return x;
return father[x] = find(father[x]);
}
int main() {
cin >> n;
en = 0;// Edge Number;
// 1. 读入边
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
int w;
cin >> w;
if (i != j) {
en ++;
e[en].u = i;
e[en].v = j;
e[en].w = w;
}
}
}
// 2. 排序边
sort(e + 1, e + en + 1, cmp);
// 3. 一条条选边
sum = 0;
for (int i = 1; i <= n; ++i) father[i] = i;
tot = 0;
for (int i = 1; i <= en; ++i) {
int u = e[i].u;
int v = e[i].v;
int root1 = find(u); // u所在集合的代表元素,根节点
int root2 = find(v); // v所在集合的代表元素,根节点
if (root1 != root2) {
sum += e[i].w;
father[root1] = root2;
tot ++;
}
if (tot == n - 1) break;
}
cout << sum;
return 0;
}
现在再放prim算法的代码(可用于时间复杂度为O(n2)的问题
#include <bits/stdc++.h>
using namespace std;
int n, sum;
int dis[1000], w[200][200];
bool vis[200];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cin >> w[i][j];
for (int i = 1; i <= n; ++i) vis[i] = false;
vis[n] = true;
for (int i = 1; i < n; ++i)
dis[i] = w[i][n]; // dis[i]表示的是第i号点走到白色点的最近的一条边长
for (int i = 1; i < n; ++i) {
int v = -1;
for (int j = 1; j <= n; ++j)
if (vis[j] == false && (v == -1 || dis[v] > dis[j]))
v = j;
if (v == -1) break;
sum += dis[v];
vis[v] = true;
for (int j = 1; j <= n; ++j)
if (vis[j] == false)
dis[j] = min(dis[j], w[v][j]);
}
cout << sum << endl;
return 0;
}
到这里,你应该能明白和复习一些基础知识了吧
后记
此文章还没结束,在本周内还会进行修改与补充
此主题我会不断进行更新,若有改进的意见,请发邮件至learning.dlq@gmail.com 或 直接评论即可。
谢谢大家的关注