第K短路[POJ2449]

版权声明:作为一个蒟蒻,转载时请通知我这个蒟蒻 https://blog.csdn.net/zyszlb2003/article/details/89433892

欢迎大家访问我的老师的OJ———caioj.cn

题面描述

给定 N N 个点, M M 条有向边,求第 K K 短路。
注意:若出发点与结束点为同一点,则一定要从出发点跑出去,再跑回来,才算最短路

思路

这道题如果直接优先队列跑的话,最坏时间复杂度为 O ( K ( N + M ) ( l o g ( N + M ) ) O(K*(N+M)*(log(N+M)) ,因为我们要跑 K K 次路径。
现提供 A A* 做法:
所谓 A A* 用人话描述就是目光要放长远脚步要够坚定,它好比有高人带着你刷副本似的,少走弯路。
比起普通优先队列, A A* 多了一个估价函数 f ( x ) f(x) ,为了保证最优解, f ( x ) f(x) 要满足一个基本准则

  1. 设当前状态 state \operatorname{state} 到目标状态所需代价的估计值为 f(state) \operatorname{f(state)}。
  2. 实际所需价值为 g(state) \operatorname{g(state)} .
  3. 对于任意的 state \operatorname{state} ,应该有 f(state) g(state) \operatorname{f(state)}\le \operatorname{g(state)}

这种带有估计函数的优先队列BFS就称为 A*(A Star) \large \operatorname{A*(A~ Star)} .只要保证 f(state) g(state) \operatorname{f(state)}\le \operatorname{g(state)} ,A*就一定能在目标状态第一次从堆中取出时得到最优解,并且在搜索过程中每个状态只需要被拓展一次
下面给出简要证明:
设当前状态 S S 并不是最优解,
S S 的“当前代价”+ f ( S ) \operatorname{\large f(S)}\ge 当前处在未来最优路径上的 T T 的“代价“+ f ( T ) \operatorname{\large f(T)} ,所以 T T 先拓展, S S 则被忽略。

第K短路则运用了 A A* 的排除多余状态与优先队列 B F S BFS ,第几次取出 e d ed ,即求到第几短路的性质来解决问题, A A* 主要起优化作用。

反向求从 e d ed 跑到 s t st 的最短路,得到估价函数 f f

后正常BFS即可。

代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e3+10;
const int inf=0x3f3f3f3f;
const int M=1e5+10;
struct edge{int x,y,d,next;}a[M],b[M];int len,last1[N],last2[N];
void ins(int x,int y,int d)
{
	a[++len].x=x,a[len].y=y;a[len].d=d;a[len].next=last1[x];last1[x]=len;
	b[len].x=y;b[len].y=x;b[len].d=d;b[len].next=last2[y];last2[y]=len;
}
struct nde
{
	int x,d;
	nde(){}
	nde(int x,int d):x(x),d(d){}
	bool operator <(const nde a)const{return d>a.d;}
};
int f[N];bool v[N];int st,ed;
void dijk_p()
{
	priority_queue<nde>q;
	memset(f,0x3f,sizeof(f));memset(v,false,sizeof(v));
	q.push(nde(ed,0));f[ed]=0;
	while(!q.empty())
	{
		nde t=q.top();q.pop();
		int x=t.x;if(v[x])continue;
		v[x]=true;
		for(int k=last2[x];k;k=b[k].next)
		{
			int y=b[k].y;
			if(f[y]>f[x]+b[k].d)
			{
				f[y]=f[x]+b[k].d;
				q.push(nde(y,f[y]));
			}
		}
	}
}
struct node
{
	int x,d,f;
	node(){}
	node(int x,int d,int f):x(x),d(d),f(f){}
	bool operator <(const node a)const{return f==a.f?d>a.d:f>a.f;}
};
int kl;
void dijk_AS()
{
	priority_queue<node>q;int cnt=0;
	if(f[st]==inf){puts("-1");return ;}
	q.push(node(st,0,f[st]));
	while(!q.empty())
	{
		node t=q.top();q.pop();
		if(t.x==ed)cnt++;
		if(kl==cnt){printf("%d\n",t.d);return ;}
		int x=t.x;
		for(int k=last1[x];k;k=a[k].next)
		{
			int y=a[k].y;
			int d=t.d+a[k].d;
			q.push(node(y,d,d+f[y]));
		}
	}
	puts("-1");
}
int main()
{
	int n,m;len=0;
	scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){int x,y, d;scanf("%d%d%d",&x,&y,&d);ins(x,y,d);}
    scanf("%d%d%d",&st,&ed,&kl);if(st==ed)kl++;
    dijk_p();
    dijk_AS();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/89433892