Poj2449 Remmarguts' Date(SPFA+第k短路+A*)

1 篇文章 0 订阅

http://poj.org/problem?id=2449


根据A*

f(p)=g(p)+h(p)

g(p)就是p点到s点最短距离

h(p)就是p点到t点的距离

h(p)的求法就是将边反过来求一遍单源最短路即可。

为什么要用A*?

A*的作用就是将普通的bfs变得更加智能,我们可以通过改变h函数来达到我们希望的效果。

这道题,我们要求第K短路,那么怎么去求呢。

思路就是利用A*,将较短的路径上的点放在前面去跑。

这样我们第一次跑到终点的路径一定是最短的。

那么我们怎么去找第K短,就是将js++,继续跑,因为此时优先队列中的点都是有序的,下一次跑到终点就一定是第二短路径。

以此类推,直到第k次找到终点,就一定是第k短的。

但是要注意,如果起点与终点一样,那么开始要将js++,因为此时最短路径为它本身这个点也就是0,所以这种情况下实际上我们要找的是第k+1短路

#include<cstdio>
#include<iostream>
#include<stack>
#include<queue>
#include<cmath> 
#include<cstring>
using namespace std;
int n,m;
struct node{
	int v;
	int nex;
	int cost;
};
node eg[555555];
node reg[555555];
int hea[555555];
int rhea[555555];
int dis[555555];
bool vis[555555];
int ss[3333333];
int e=0;
struct As{
	int p;
	int g;
	int f;
	bool operator <(const As a)const{
		if(f==a.f)return g>a.g;
		return f>a.f;
	}
};
void insert(int st,int ed,int cost)
{
	eg[e].v=ed;
	eg[e].cost=cost;
	eg[e].nex=hea[st];
	hea[st]=e;
	reg[e].v=st;
	reg[e].cost=cost;
	reg[e].nex=rhea[ed];
	rhea[ed]=e++;
}
void spfa(int st)
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	int h=0;
	int r=1;
	ss[h]=st;
    dis[st]=0;
    int tt;
    while(h<r)
    {
    	tt=ss[h];
    	vis[tt]=0;
    	h++;
    	for(int i=rhea[tt];i!=-1;i=reg[i].nex)
    	{
    		if(dis[reg[i].v]>dis[tt]+reg[i].cost)
    		{
    			dis[reg[i].v]=dis[tt]+reg[i].cost;
    			if(vis[reg[i].v]==0)
    			{
    			    ss[r++]=reg[i].v;
    			    vis[reg[i].v]=1;
				}
			}
		}
	}
}
int astar(int st,int ed,int k)
{
	priority_queue<As> qu;
	if(st==ed)k++;
	int js=0;
	As t,tt;
	t.p=st;
	t.g=0;
	t.f=t.g+dis[st];
	qu.push(t);
	while(!qu.empty())
	{
	     tt=qu.top();
	     qu.pop();
	     if(tt.p==ed)
	     {
	     	js++;
	     	if(js==k)
	     	return tt.g;
		 }
	     for(int i=hea[tt.p];i!=-1;i=eg[i].nex)
	     {
	     	t.p=eg[i].v;
	     	t.g=tt.g+eg[i].cost;
	     	t.f=t.g+dis[eg[i].v];
	     	qu.push(t);
		 }
	}
	return -1;
}
int main(){
	while(scanf("%d%d", &n, &m) != EOF)
	{
		e=0;
		int st,ed,cost;
		int s,t,k;
		memset(hea,-1,sizeof(hea));
		memset(rhea,-1,sizeof(rhea));
		for(int i=0;i<m;i++)
		{
			cin>>st>>ed>>cost;
			insert(st,ed,cost);
		}
		cin>>s>>t>>k;
		spfa(t);
		//for(int i=1;i<=n;i++)
		//cout<<dis[i]<<" "<<endl;
		if(dis[s]==0x3f3f3f3f)
		{
			cout<<"-1"<<endl;
		}
		else 
		cout<<astar(s,t,k)<<endl;
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值