HDU - 2544 最短路(经典题:一题多解)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544

Problem Description
在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

Floyd算法:
复杂度为(n3)

#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100 + 5;
int g[maxn][maxn], N, M;
int main(void) {
	while (~scanf("%d %d", &N, &M) && N) {
		for (int i = 1; i <= N; i++)
			for (int j = 1; j <= N; j++) {
				if (i != j) g[i][j] = inf;
				else g[i][j] = 0;
			}
		for (int i = 0; i < M; i++) {
			int A, B, C;
			scanf("%d %d %d", &A, &B, &C);
			g[A][B] = C; g[B][A] = C;
		}
		for (int k = 1; k <= N; k++)
			for (int i = 1; i <= N; i++)
				if (k != i) 
					for (int j = 1; j <= N; j++)
						if (i != j && g[i][k] + g[k][j] < g[i][j]) 
							g[i][j] = g[i][k] + g[k][j];										
		printf("%d\n", g[1][N]);
	}
	return 0;
}

Bellman-Ford算法:

#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m, w[maxn][maxn];
void bellman() {
	int s = 1, d[maxn];
	for (int i = 1; i <= n; i++)
		d[i] = inf;
	d[s] = 0;
	for (int k = 1; k <= n; k++)//一轮操作最少得到1个点的最短距离
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)//通过相邻点的距离不断更新最短距离
				if (d[j] > d[i] + w[i][j])
					d[j] = d[i] + w[i][j];
	printf("%d\n", d[n]);
}
int main(void) {
	while (~scanf("%d %d", &n, &m) && n) {
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				if (i != j)w[i][j] = inf;
				else w[i][j] = 0;
		for (int i = 0; i < m; i++) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			w[a][b] = w[b][a] = c;
		}
		bellman();
	}
	return 0;
}

上述编码没有发挥Bellman-Ford的优势,其复杂度为O(n3)

下述代码则为O(nm)

#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m, cnt;
struct edge {
	int u, v, w;
}e[10005];
void bellman() {
	int s = 1, d[maxn];
	for (int i = 1; i <= n; i++)
		d[i] = inf;
	d[s] = 0;//这里还可以修改一下判断可以更快
	for (int k = 1; k <= n; k++)//一轮操作最少得到1个点的最短距离
		for (int i = 0; i < cnt; i++) {
			int x = e[i].u, y = e[i].v;
			if (d[x] > d[y] + e[i].w)
				d[x] = d[y] + e[i].w;
		}
	printf("%d\n", d[n]);
}
int main(void) {
	while (~scanf("%d %d", &n, &m) && n) {
		cnt = 0;
		for (int i = 0; i < m; i++) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			e[cnt].u = a; e[cnt].v = b; e[cnt].w = c; cnt++;
			e[cnt].u = b; e[cnt].v = a; e[cnt].w = c; cnt++;
		}
		bellman();
	}
	return 0;
}

SFPA算法:
Bellman-Ford的优化版

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m;
struct edge {
	int from, to, w;
	edge(int a, int b, int c) :from(a), to(b), w(c) {}
};
vector<edge>e[maxn];
void spfa(int s) {//相当于对Bellman-Ford的优化,使用队列减少了很多无效操作
	int dis[maxn];
	bool inq[maxn];
	for (int i = 1; i <= n; i++) {
		dis[i] = inf; inq[i] = false;
	}
	dis[s] = 0;
	queue<int>Q;
	Q.push(s);
	inq[s] = true;
	while (!Q.empty()) {
		int u = Q.front(); Q.pop();
		inq[u] = false;
		for (int i = 0; i < e[u].size(); i++) {
			int v = e[u][i].to, w = e[u][i].w;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (!inq[v]) {
					inq[v] = true;
					Q.push(v);
				}
			}
		}
	}
	printf("%d\n", dis[n]);
}
int main(void) {
	while (~scanf("%d %d", &n, &m) && n) {
		for (int i = 1; i <= n; i++)e[i].clear();
		for (int i = 0; i < m; i++) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			e[a].push_back(edge(a, b, c));
			e[b].push_back(edge(b, a, c));
		}
		spfa(1);
	}
	return 0;
}

链式向前星!
相关知识:https://blog.csdn.net/flymoyu/article/details/90319846

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1000005;
int n, m, cnt, head[maxn];
struct edge {
	int to, w, nxt;
}e[maxn];
void init() {
	for (int i = 0; i < maxn; i++) {
		e[i].nxt = -1;
		head[i] = -1;
	}
	cnt = 0;
}
void addedge(int u, int v, int w) {//向前星
	e[cnt].to = v;
	e[cnt].w = w;
	e[cnt].nxt = head[u];
	head[u] = cnt++;
}
void spfa(int s) {
	int dis[maxn];
	bool inq[maxn];
	for (int i = 1; i <= n; i++) {
		dis[i] = inf; inq[i] = false;
	}
	dis[s] = 0;
	queue<int>Q;
	Q.push(s);
	inq[s] = true;

	while (!Q.empty()) {
		int u = Q.front(); Q.pop();
		inq[u] = false;
		for (int i = head[u]; ~i; i = e[i].nxt) {
			int v = e[i].to;
			if (dis[v] > dis[u] + e[i].w) {
				dis[v] = dis[u] + e[i].w;
				if (!inq[v]) {
					inq[v] = true;
					Q.push(v);
				}
			}
		}
	}
	printf("%d\n", dis[n]);
}
int main(void) {
	while (~scanf("%d %d", &n, &m) && n) {
		init();
		for (int i = 0; i < m; i++) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			addedge(a, b, c);
			addedge(b, a, c);
		}
		spfa(1);
	}
	return 0;
}

SFPA算法的效率和图的权有关,是不稳定的

下面是Dijkstra算法(稳定)

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;
int n, m;
struct edge {
	int from, to, w;
	edge(int a, int b, int c) :from(a), to(b), w(c) {}
};
vector<edge>e[maxn];
struct node{
	int id, dis;
	node(int b, int c) {
		id = b; dis = c;
	}
	bool operator <(const node& a)const {
		return dis > a.dis;
	}
};
void dijkstra() {
	int s = 1;
	int dis[maxn];
	bool done[maxn];
	for (int i = 1; i <= n; i++) {
		dis[i] = inf; done[i] = false;
	}
	dis[s] = 0;
	priority_queue<node>pq;
	pq.push(node(s, dis[s]));
	while (!pq.empty()) {
		node u = pq.top(); pq.pop();//用距离s最近的点u
		if (done[u.id])continue;//已经找到最短了,跳过
		done[u.id] = true;//当前就是最短的距离,相当于放入A集合
		for (int i = 0; i < e[u.id].size(); i++) {
			edge y = e[u.id][i];
			if (done[y.to])continue;
			if (dis[y.to] > u.dis + y.w) {//更新备选点
				dis[y.to] = u.dis + y.w;
				pq.push(node(y.to, dis[y.to]));
			}
		}
	}
	printf("%d\n", dis[n]);
}
int main(void) {
	while (~scanf("%d %d", &n, &m) && n) {
		for (int i = 1; i <= n; i++)e[i].clear();
		while (m--) {
			int a, b, c;
			scanf("%d %d %d", &a, &b, &c);
			e[a].push_back(edge(a, b, c));
			e[b].push_back(edge(b, a, c));
		}
		dijkstra();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JILIN.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值