Dijkstra算法与SPFA算法

最近看了《算法笔记》上面关于最短路径的部分,学习了一种之前没见过的算法:SPFA。
理论上SPFA算法会比Dijkstra快,顾而找了一题测试一下。

使用PAT A1072题,因为这题求最短路径的部分很单纯,没有其他的权,而且测试点的复杂度够高,能够看出时间上的差别。

题目链接

速度对比(重点看测试点4)

Dijkstra速度

![image.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC9wbmcvOTMyMzYwLzE1OTE5NzU5ODI2NjItZmU5YThmYTctYzZhOC00M2U0LWEyYzctZDBlYzY3NjMyY2U2LnBuZw?x-oss-process=image/format,png#align=left&display=inline&height=220&margin=[object Object]&name=image.png&originHeight=220&originWidth=913&size=14208&status=done&style=none&width=913)

SPFA

![image.png](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC9wbmcvOTMyMzYwLzE1OTE5NzU5NDc4MDQtMzI1YWFjMjItNDUwMy00ZmQ4LTk2YWMtYWU2ODZiNGM3NTA5LnBuZw?x-oss-process=image/format,png#align=left&display=inline&height=231&margin=[object Object]&name=image.png&originHeight=231&originWidth=915&size=12841&status=done&style=none&width=915)
多次提交对比,Dijkstra算法都在50ms左右,而SPFA一直在10ms左右,可见SPFA确实比Dijkstra快不少,而且思路也不复杂,以后可以多多使用。

代码如下

#include
#include
using namespace std;
#define MAXNODE 1015
#define INF 0x3ffffff
#define G2index(G) ((n)+(G))
#define index2G(index) ((index)-(G))

struct Node
{
	int v, dis;//目标与距离
};

int dis[MAXNODE];
int n, m, k, dmax;
bool used[MAXNODE], inqueue[MAXNODE];
vector<Node> graph[MAXNODE];

void Dijkstra(int start)
{
	fill(dis, dis + MAXNODE, INF);
	fill(used, used + MAXNODE, false);
	dis[start] = 0;

	for (int i = 0; i < n + m - 1; i++) {
		int minnode = -1, mindis = INF;
		for (int j = 1; j <= n + m; j++) {
			if (!used[j] && dis[j] < mindis) {
				minnode = j;
				mindis = dis[j];
			}
		}
		if (minnode == -1)
			return;

		used[minnode] = true;
		int tdis = dis[minnode];
		for (Node node : graph[minnode]) {
			if (tdis + node.dis < dis[node.v]) {
				dis[node.v] = tdis + node.dis;
			}
		}
	}
}

void SPFA(int start)
{
	fill(dis, dis + MAXNODE, INF);
	fill(inqueue, inqueue + MAXNODE, false);
	dis[start] = 0;

	int tdis = 0;
	queue<int> q;
	for (Node node : graph[start]) {
		if (tdis + node.dis < dis[node.v]) {
			dis[node.v] = node.dis + tdis;
			q.push(node.v);
			inqueue[node.v] = true;
		}
	}
	while (!q.empty()) {
		int nodeid = q.front();
		q.pop();
		inqueue[nodeid] = false;
		for (Node node : graph[nodeid]) {
			tdis = dis[nodeid];
			if (tdis + node.dis < dis[node.v]) {
				dis[node.v] = node.dis + tdis;
				if (!inqueue[node.v]) {
					q.push(node.v);
					inqueue[node.v] = true;
				}
			}
		}
	}
}

struct Ans
{
	int Gid, mindis, totaldis;
};
vector<Ans> ans;

void getans(int Gid)
{
	int totaldis, mindis;
	mindis = INF;
	totaldis = 0;
	for (int i = 1; i <= n; i++) {
		if (dis[i] > dmax)
			return;
		if (dis[i] < mindis) {
			mindis = dis[i];
		}
		totaldis += dis[i];
	}
	ans.push_back(Ans{ Gid,mindis,totaldis });
}

int main() {
	scanf("%d%d%d%d", &n, &m, &k, &dmax);
	for (int i = 0; i < k; i++) {
		int c1, c2, dd;
		char cs1[10], cs2[10];
		scanf("%s%s%d", cs1, cs2, &dd);
		if (cs1[0] == 'G') {
			c1 = G2index(atoi(cs1 + 1));
		}
		else {
			c1 = atoi(cs1);
		}

		if (cs2[0] == 'G') {
			c2 = G2index(atoi(cs2 + 1));
		}
		else {
			c2 = atoi(cs2);
		}
		graph[c1].push_back(Node{ c2, dd });
		graph[c2].push_back(Node{ c1, dd });
	}
	for (int i = 1; i <= m; i++) {
		//Dijkstra(G2index(i));
		SPFA(G2index(i));
		getans(i);
	}

	Ans myans;
	myans.Gid = -1;
	myans.totaldis = INF;
	myans.mindis = 0;
	for (Ans a : ans) {
		if (a.mindis > myans.mindis)
			myans = a;
		else if (a.mindis == myans.mindis) {
			if (a.totaldis < myans.totaldis)
				myans = a;
		}
	}
	if (myans.Gid == -1) {
		printf("No Solution");
		return 0;
	}
	printf("G%d\n%.1lf %.1lf", myans.Gid, (double)myans.mindis, (double)myans.totaldis / n);
	return 0;
}

代码思路就不写了,大家可以看算法笔记。

打个广告:原博地址

你可能感兴趣的:(PAT)