多种方式计算最短路径

朴素算法实现方式:

#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
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值