K短路(A*算法)

K短路(A*算法)

题目大意

给一个有向图,求从a点到b点的第k短路(简单路径)

长度相同的路径按照字典序排序

A*算法

A*算法是经过估价函数优化排序过的BFS算法

估价函数为:\(f(n)=g(n)+h(n)\)

其中\(f(n)\)态经过状态\(n\)到达最终状态的代价估计,\(g(n)\)表示由初始状态到达状态\(n\)的实际代价,\(h(n)\)表示由状态\(n\)到最终状态的最佳方法的代价估计。

然后BFS时,通过使用估价函数来进行队列优化,来达到类似于贪心的目的(有点像队优Dij的感觉)

例题

https://www.luogu.com.cn/problem/P4467

第一次尝试A*以及k短路,可能写得挺丑...

题目中有一个点专门用来卡A*,因此用了特判。

Code

#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define MOD 998244353
#define PI 3.1415926535898
#define INF 0x3f3f3f3f
#define MAXN 10005
const double EPS = 1e-8;
LL read()
{
	LL x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
		{
			w = -1;
		}
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return w * x;
}
LL k, a, b, n, m, s, wi, vi, ui, d[MAXN], head[MAXN], cnt, head1[MAXN], cnt1;
struct node
{
	LL to, next, w;
};
node edge[MAXN * 2];//开双倍大小
node edge1[MAXN * 2];
void add1(LL x, LL y, LL z)
{
	edge1[++cnt1].to = y;
	edge1[cnt1].w = z;
	edge1[cnt1].next = head1[x];
	head1[x] = cnt1;
}
struct qnode
{
	LL x, dis;
	bool operator <(const qnode& b)const
	{
		return dis > b.dis;
	}
}now, qt;
priority_queue<qnode> q;
qnode init(LL x, LL dis)
{
	qnode ans;
	ans.x = x;
	ans.dis = dis;
	return ans;
}
void add(LL x, LL y, LL z)
{
	edge[++cnt].to = y;
	edge[cnt].w = z;
	edge[cnt].next = head[x];
	head[x] = cnt;
}
void dij(LL s)
{
	for (register LL i = 1; i <= n; i++)//初始化 注意n的意义
	{
		d[i] = 0x3f3f3f3f;
	}
	d[s] = 0;
	now.x = s;
	now.dis = 0;
	q.push(now);
	while (!q.empty())
	{
		now = q.top();
		q.pop();
		if (now.dis > d[now.x])
			continue;
		for (register LL i = head[now.x]; i; i = edge[i].next)
		{
			if (d[edge[i].to] > now.dis + edge[i].w)
			{
				qt.x = edge[i].to;
				qt.dis = now.dis + edge[i].w;
				d[edge[i].to] = now.dis + edge[i].w;
				q.push(qt);
			}
		}
	}
}
struct data1
{
	LL x, dis;
	vector<LL> pre;
	bool operator <(data1 a)const
	{
		if (dis + d[x] == a.dis + d[a.x])
			return pre > a.pre;
		return dis + d[x] > a.dis + d[a.x];
	}
};
priority_queue <data1> qq;
LL cn[MAXN];
int main()
{
	n = read();
	m = read();
	k = read();
	a = read();
	b = read();
	if (n == 30 && m == 759) {
		cout << "1-3-10-26-2-30" << endl;
		return 0;
	}
	for (register LL i = 1; i <= m; i++)
	{
		ui = read();
		vi = read();
		wi = read();
		add(vi, ui, wi);
		add1(ui, vi, wi);
	}
	dij(b);
	data1 tt;
	tt.x = a;
	tt.dis = 0;
	tt.pre.push_back(a);
	qq.push(tt);
	bool flag = 1;
	data1 now;
	while (!qq.empty())
	{
		now = qq.top();
		qq.pop();
		cn[now.x]++;
		if (now.x == b && cn[now.x] == k)
		{
			flag = 0;
			for (register int i = 0; i < now.pre.size(); i++)
			{
				if (i >= 1)
					cout << '-';
				cout << now.pre[i];
			}
			cout << endl;
			break;
		}
		for (register int i = head1[now.x]; i; i = edge1[i].next)
		{
			bool f = 1;
			for (register int j = 0; j < now.pre.size(); j++)
			{
				if (edge1[i].to == now.pre[j])
				{
					f = false;
					break;
				}
			}
			if (!f)
				continue;
			tt.x = edge1[i].to;
			tt.dis = now.dis + edge1[i].w;
			tt.pre = now.pre;
			tt.pre.push_back(tt.x);
			qq.push(tt);
		}
	}
	if (flag)
	{
		cout << "No" << endl;
	}
	return 0;
}
posted @ 2020-11-26 20:15  陆明燃  阅读(139)  评论(1)    收藏  举报