朴素算法实现方式:
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1001;
int d[N];//记录最短路径的生成距离
int p[N][N];//记录原始点到点的数据,这里采用矩阵记录点到点的距离
bool use[N];//记录该点是否被使用
int n, m;
void dijk_algorithm() {
memset(d, 0x3f, sizeof d);
d[1] = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 0; j < n; j++) {
if (!use[j] && (t = -1 || d[t] > d[j])) {
t = j;
}
use[t] = true;
for (int j = 1; j <= n; j++) {
d[j] = min(d[j], d[t] + p[t][j]);
}
}
}
if (d[n] == 0x3f3f3f3f) printf("-1\n");//一定要是0x3f3f3f;,不然不是最大值 .
else printf("%d\n", d[n]);
}
int main()
{
cin >> n >> m;
memset(p, 0x3f, sizeof p);
for (int i = 0; i < m; i++) {
int x, y, d;
cin >> x >> y >> d;
p[x][y] = min(p[x][y], d);
}
dijk_algorithm();
return 0;
}
最小堆实现方式:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1001;
typedef pair<int, int> PII;
int d[N];//记录最短路径的生成距离
bool use[N];//记录该点是否被使用
int e[N], ne[N], h[N], id, w[N];
int n, m;
void add(int a, int b, int c) {
e[id] = b, w[id] = c, ne[id] = h[a], h[a] = id++;
}
void dijk_algorithm() {
memset(d, 0x3f, sizeof d);
d[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({ 0,1 });
while (heap.size()) {
auto t = heap.top();
heap.pop();
int distance = t.first, ver = t.second;
if (use[ver]) continue;
for (int i = h[ver]; i != -1; i = ne[i]) {
int j = e[i];
if (d[j] > distance + w[i]) {//这里对所有的相关联的点进行更新,同时讲这个点加入小点堆.
d[j] = distance + w[i];
heap.push({ d[j],j });
}
}
}
if (d[n] == 0x3f3f3f3f) printf("-1\n");//一定要是0x3f3f3f;,不然不是最大值 .
else printf("%d\n", d[n]);
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int x, y, d;
cin >> x >> y >> d;
add(x, y, d);
}
dijk_algorithm();
return 0;
}
bellman-ford 方式, 适用于有有负权边,在有限步骤里面到达终点的情况
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1001, M = 10010;
int n, m, k;
int d[N], backup[N];
struct Edge {
int a, b, w;
}edges[M];
void dijk_algorithm() {
memset(d, 0x3f, sizeof d);
d[1] = 0;
for (int i = 0; i < k; i++) {
memcpy(backup, d, sizeof d);
for (int j = 0; j < m; j++) {
int a = edges[j].a, b = edges[j].b, w = edges[j].w;
d[b] = min(d[b], backup[a] + w);
}
}
if (d[n] > 0x3f3f3f3f / 2) printf("-1");
else printf("%d\n", d[n]);
}
int main()
{
cin >> n >> m>>k;
for (int i = 0; i < m; i++) {
int x, y, d;
cin >> x >> y >> d;
edges[i] = { x,y,d };
}
dijk_algorithm();
return 0;
}
SPFA法, 适用于有负权边但是没有环, 一般复杂度O(m),最坏复杂度O(nm);
#include <iostream>
#include<cstring>
#include<algorithm>
#include <queue>
using namespace std;
const int N = 10010;
int e[N], ne[N], h[N], w[N], id;
bool st[N];
int dist[N];
int n, m;
void add(int a, int b, int c) {
e[id] = b, ne[id] = h[a], w[id] = c, h[a] = id++;
}
void spfa() {
queue<int> q;
q.push(1);
st[1] = true;
dist[1] = 0;
while (q.size()) {
int t = q.front();
st[t] = false;
q.pop();
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];//利用邻接表,每次只更新当前这个节点相关的邻接结点
if (dist[j] > dist[t] + w[i]){
dist[j] = dist[t] + w[i];
if (!st[j]) q.push(j);
}
}
}
if (dist[n] == 0x3f3f3f3f) printf("impossible \n");
else printf("%d", dist[n]);
}
int main() {
memset(h, -1, sizeof h);
memset(dist, 0x3f, sizeof dist);
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
spfa();
return 0;
}
使用 spfa 算法判断是否有环的的话,需要增加加一个计数数组cnt[t],没更更新一次计数值就加一,当cnt[t]>n,的时候,就表明图中存在环.
#include <iostream>
#include<cstring>
#include<algorithm>
#include <queue>
using namespace std;
const int N = 10010;
int e[N], ne[N], h[N], w[N], id;
bool st[N];
int cnt[N];
int dist[N];
int n, m;
void add(int a, int b, int c) {
e[id] = b, ne[id] = h[a], w[id] = c, h[a] = id++;
}
int spfa() {
queue<int> q;
for (int i = 1; i <= n; i++) {
q.push(i);
}
st[1] = true;
dist[1] = 0;
while (q.size()) {
int t = q.front();
st[t] = false;
q.pop();
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];//利用邻接表,每次只更新当前这个节点相关的邻接结点
if (dist[j] > dist[t] + w[i]){
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if (cnt[j] > n) {
return 0;
}
if (!st[j]) q.push(j);
}
}
}
if (dist[n] == 0x3f3f3f3f) return -1;
else return 1;
}
int main() {
memset(h, -1, sizeof h);
memset(dist, 0x3f, sizeof dist);
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
if (spfa()==0) printf("有负权环\n");
if (dist[n] == 0x3f3f3f3f) printf("impossible\n");
else printf("%d\n ", dist[n]);
return 0;
}
//测试用例
/*
5 5
1 2 2
2 3 2
3 5 2
3 4 -2
4 2 -1
*/