POJ 3255 解题报告

这道题是求次短路径。做法比我想象的简单。思路和求最短路径基本一样,只是同时更新最短和次短路径,所以Dijkstra, SPFA等在这里依然可以用。这里用的是SPFA。

更新次短路径的逻辑已经比较复杂了。次短路径的来源可能是:

1. 该节点的最短路径。如果发现了新的最短路径,那么次短路径就是旧的最短路径。

2. 邻接节点的最短路径。邻接节点的最短路径加上一跳可能比该点的最短路径大,但可能比次短路径小。

3.邻接节点的次短路径。与上面类似,可能会发现该节点新的次短路径。

我猜如果问题求k短路径的时候上述更新逻辑已经过于复杂,有的解题报告中提到的A*可能是正确的做法。

测试数据:

5 10
1 2 1982
2 3 3963
3 4 2046
3 5 1353
4 2 1370
4 1 2192
5 3 2898
4 3 1395
4 1 3722
3 2 4596
(5591)


4 6
1 2 1
1 2 5
1 3 2
2 3 2
2 4 1
2 4 6
(4)

thestoryofsnow3255Accepted2588K219MSC++1781B

/* 
ID: thestor1 
LANG: C++ 
TASK: poj3255 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

const int INF = 5000 * 5000;

class Edge
{
public:
	int v, w;
	Edge() {}
	Edge(int v, int w) : v(v), w(w) {}
};

int main()
{
	int N, R;
	scanf("%d%d", &N, &R);
	std::vector<vector<Edge> > adjs(N, std::vector<Edge>());
	for (int r = 0; r < R; ++r) {
		int A, B, D;
		scanf("%d%d%d", &A, &B, &D);
		A--, B--;

		adjs[A].push_back(Edge(B, D));
		adjs[B].push_back(Edge(A, D));
	}

	// Shortest-Path-Faster-Algorithm 
	// see https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
	vector<vector<int> > dis(N, vector<int>(2));
	for (int i = 0; i < N; ++i) {
		dis[i][0] = dis[i][1] = INF;
	}

	const int source = 0;
	dis[source][0] = 0;

	queue<int> que;
	std::vector<bool> isInQueue(N, false);
	que.push(source);
	isInQueue[source] = true;
	while (!que.empty()) {
		int u = que.front();
		que.pop();
		isInQueue[u] = false;

		for (int i = 0; i < adjs[u].size(); ++i) {
			int v = adjs[u][i].v, w = adjs[u][i].w;
			int nd = dis[u][0] + w;

			bool updated = false;
			if (nd < dis[v][0]) {
				dis[v][1] = dis[v][0];
				dis[v][0] = nd;
				updated = true;
			}

			if (nd > dis[v][0] && nd < dis[v][1]) {
				dis[v][1] = nd;
				updated = true;
			} else {
				nd = dis[u][1] + w;
				if (nd > dis[v][0] && nd < dis[v][1]) {
					dis[v][1] = nd;
					updated = true;
				}
			}

			if (updated && !isInQueue[v]) {
				que.push(v);
				isInQueue[v] = true;
			}
		}
	}

	const int sink = N - 1;
	printf("%d\n", dis[sink][1]);

	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值