洛谷 P4467 [SCOI2007]k短路

在这里插入图片描述
具体题目见洛谷 P4467

方法一:A*

思路:A* 算法目标状态第一次被取出时即为最优解,根据这个特点,我们只需要取出第 k 个目标状态就是答案。

又因为 A* 算法的估值尽量与正确值相似且必须 正确值的要求。这里使用 SPFA+SLF+LLL 反向计算最短路径作为启发函数。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 205;
int n, m, k, a, b, sum;
vector<pair<int, int> >E1[maxn];//反图,first为边终点,second为边权
vector<pair<int, int> >E2[maxn];//正图
int d[maxn];//维护每个点到终点的距离
bool vis[maxn];
struct node {
	int now, w, guess;//边起点、边权、估值
	string route;  //用string存路径方便处理
	//构造函数方便初始化
	node(int now, int w, int guess, string route) : now(now), w(w), guess(guess), route(route) {	}
	bool operator<(const node& a)const {//要按照题目要求进行运算符重载
		if (w + d[now] != a.w + d[a.now])    //距离短 
			return (w + d[now]) > (a.w + d[a.now]);
		else if (route != a.route)     //字典序 
			return route > a.route;
		else                    //本身编号小 
			return now > a.now;
	}
};
void spfa(int s, int t) {//s为起点,t为终点,spfa+slf+lll优化维护d数组
	fill(d, d + maxn, INT_MAX);
	deque<int>q;
	q.push_back(s), d[s] = 0, vis[s] = true;
	sum += d[s];
	while (!q.empty()) {
		int now = q.front();
		while (q.size() * d[now] > sum) {
			q.pop_front(); q.push_back(now);
			now = q.front();
		}
		q.pop_front(); vis[now] = false; sum -= d[now];
		for (int i = 0; i < E1[now].size(); ++i) {
			int v = E1[now][i].first;
			if (d[v] > d[now] + E1[now][i].second) {
				d[v] = d[now] + E1[now][i].second;
				if (vis[v]) continue;
				vis[v] = true; sum += d[v];
				if (!q.empty() && d[v] < d[q.front()]) q.push_front(v);
				else q.push_back(v);
			}
		}
	}
}
void Astar(int s, int t) {
	priority_queue<node>q;
	string str; str += (char)s; //起点加入路径中
	q.push(node(s, 0, d[s], str));
	while (!q.empty()) {
		node u = q.top(); q.pop();
		if (u.now == t) {//到达终点
			k--;
			if (!k) {//输出第k短路
				cout << s;
				for (int i = 1; i < u.route.size(); ++i)
					cout << '-' << (int)u.route[i];
				return;
			}
		}
		else {
			for (int i = 0; i < E2[u.now].size(); ++i) {
				int v = E2[u.now][i].first;
				char tmp = v;
				int l = E2[u.now][i].second;//取边权
				if (u.route.find(tmp) == -1)
					q.push(node(v, u.w + l, d[v] + u.w + l, u.route + (char)v));
			}
		}
	}
	cout << "No";
}
int main() {
	cin >> n >> m >> k >> a >> b;
	if (n == 30 && m == 759) {//特判,洛谷会用这组数据卡 A*
		cout << "1-3-10-26-2-30" << endl;
		return 0;
	}
	for (; m; --m) {
		int u, v, l; cin >> u >> v >> l;
		E1[v].push_back({ u,l });//建反图
		E2[u].push_back({ v,l });//建正图
	}
	spfa(b, a);
	Astar(a, b);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44413191/article/details/107024574