求单点的最短路径(C++语言)

求从指定源点出发到各个顶点的最短路径。

假设:图中结点名均为单个互不相同的字母,权值均>0。

输入:
    第一行:结点数量n,弧数量e,源点
    后续e行:<结点,结点,权值>

输出:
    按结点的升序输出到达各个结点的最短路径长度


样例

输入(1)

7,10,a
<a,b,13>
<a,c,8>
<c,d,5>
<d,e,6>
<a,e,30>
<a,g,32>
<b,g,7>
<b,f,9>
<e,f,2>
<f,g,17>

输出(1)

a:0
b:13
c:8
d:13
e:19
f:21
g:20

输入(2)

5,9,a
<a,b,10>
<b,a,20>
<a,d,50>
<a,e,45>
<b,c,15>
<c,d,20>
<c,e,5>
<d,e,10>
<e,c,30>

输出(2)

a:0
b:10
c:25
d:45
e:30

输入(3)

5,7,a
<a,b,10>
<b,c,50>
<a,d,30>
<a,e,100>
<c,e,10>
<d,c,20>
<d,e,60>

输出(3)

a:0
b:10
c:50
d:30
e:60

代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f;
int road[1010][1010], d[1010];
bool vis[1010];
int n, m, num = 0;

void dijkstra(int s)//dijkstra算法
{
	for (int i = 0; i < n; i++)
	{
		d[i] = road[s][i];
		vis[i] = false;
	}
	d[s] = 0;
	vis[s] = true;
	for (int i = 0; i < n; i++)
	{
		int temp = inf, v;
		for (int j = 0; j < n; j++)
		{
			if (!vis[j] && temp > d[j])
			{
				temp = d[j];
				v = j;
			}
		}
		if (temp == inf)
			break;
		vis[v] = true;
		for (int j = 0; j < n; j++)
		{
			if (!vis[j] && d[v] + road[v][j] < d[j])
			{
				d[j] = d[v] + road[v][j];
			}
		}
	}
}
int main()
{
	int x, y, dis;
	char a, b, c;
	scanf("%d,%d,%c", &m, &n, &c);
	getchar();					//读取换行符
	for (int i = 0; i < n; i++)//初始化
	{
		for (int j = 0; j < n; j++)
		{
			road[i][j] = (i == j) ? 0 : inf;
		}
	}
	for (int i = 0; i < n; i++)
	{
		scanf("<%c,%c,%d>", &a, &b, &dis);
		getchar();
		x = a - 'a';//把字符转化为数字来算
		y = b - 'a';
		if(road[x][y]>dis)
			road[x][y]= dis;
	}
	num = c - 'a';
	dijkstra(num);
	for (int i = 0; i < m; i++)
	{
		printf("%c:%d\n", i + 'a', d[i]);//记得转回字符
	}
	//system("pause");
	return 0;
}
单元最短路径算法有多种实现方式,其中比较常用的是Dijkstra算法和Bellman-Ford算法。下面给出它们的C++实现。 1. Dijkstra算法 Dijkstra算法用于解从起点到终点的最短路径,要边的权值非负。算法的基本思想是从起点开始,每次找到当前距离起点最近的一个点,然后用该点更新其它点的距离,直到到达终点或者所有点都被访问过。 下面是Dijkstra算法C++实现: ```c++ #include <iostream> #include <vector> #include <queue> #include <cstring> #include <algorithm> using namespace std; const int N = 100010, INF = 0x3f3f3f3f; int n, m, s, t; int h[N], e[N], w[N], ne[N], idx; int dist[N]; bool st[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } void dijkstra() { memset(dist, 0x3f, sizeof dist); dist[s] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q; q.push({0, s}); while (q.size()) { auto t = q.top(); q.pop(); int ver = t.second, distance = t.first; if (st[ver]) continue; st[ver] = true; for (int i = h[ver]; ~i; i = ne[i]) { int j = e[i]; if (dist[j] > distance + w[i]) { dist[j] = distance + w[i]; q.push({dist[j], j}); } } } } int main() { memset(h, -1, sizeof h); cin >> n >> m >> s >> t; while (m -- ) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } dijkstra(); cout << (dist[t] == INF ? -1 : dist[t]) << endl; return 0; } ``` 2. Bellman-Ford算法 Bellman-Ford算法用于解任意两点之间的最短路径,要边的权值可以是负数。算法的基本思想是对所有的边进行n-1次松弛操作,其中n是图中点的个数。如果在第n-1次松弛操作后仍然存在松弛的情况,说明图中存在负环,即从起点出发可以无限循环地减小距离。 下面是Bellman-Ford算法C++实现: ```c++ #include <iostream> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int N = 100010, INF = 0x3f3f3f3f; int n, m, s, t; int h[N], e[N], w[N], ne[N], idx; int dist[N], cnt[N]; bool st[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } bool spfa() { memset(dist, 0x3f, sizeof dist); dist[s] = 0; queue<int> q; q.push(s); st[s] = true; cnt[s] = 1; while (q.size()) { int t = q.front(); q.pop(); st[t] = false; for (int i = h[t]; ~i; 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 true; if (!st[j]) { q.push(j); st[j] = true; } } } } return false; } int main() { memset(h, -1, sizeof h); cin >> n >> m >> s >> t; while (m -- ) { int a, b, c; cin >> a >> b >> c; add(a, b, c); } if (spfa()) puts("-1"); else cout << dist[t] << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值