A*搜索+k短路

题目连接 传送门

 

分析:

参考传送门

前言:最短路算法是我们非常熟悉的了。Dijkstra,SPFA等单源最短路算法是我们在竞赛中常用的算法。那么,假如题目要求的不是最短的呢?

Question(1):给定一个图,求次短路。

对于次短路,很容易想到在比较的时候进行处理。

设dis(u)为原点s到u的最短路径,u为当前节点,v和u有边相连。

x = dis[v] + f[u][v];

则对于最短路:if(dis[u] > x) dis[u] = x;

而对于次短路:

if(dis[u]>x) dis2[u]=dis[u],dis[u]=x;

else if(dis2[u]>x) dis2[u]=x;

所以,对于次短路,只需加多一个数组即可。

 

那么,K短路呢?

Question(2):给定一个图,求第K短路。

对于这个问题,可以用A*算法+Dijkstra解决。

 

先了解一下A*算法:

A*算法是一种典型的启发式搜索算法。定义:

h*(s)为状态s到目标的距离

h(s)为估价函数,状态s到目标距离的下界,即h(s)<=h*(s)

g(s)为到达状态s所需的代价

f(s)为s的启发函数。有f(s) = h(s) + g(s)。

 

那么,对于本题:h(s)就是源点到s的距离,g(s)为到终点t的实际距离。

如果能求出g,那么,当A*搜索了终点k次后,当前的h就为答案。

求函数g的方法:因为g(s)为到终点t的实际距离,所以,可以把原图的边反向后,把终点改成源点,跑一次Dijkstra,算出每一个点u到t的距离,就是所求的g。

 

#include
#include
#include
#include
using namespace std;

const int maxn=1010,ed=10010;
int n,m,s,en,k,t;
int dis[maxn],times[maxn];
bool vis[maxn];

struct edge
{
	int to,next,val;
}e[ed],eo[ed];

int head[maxn],heado[maxn];

struct anode
{
	int p,g,h;
	bool operator < (anode x) const
	{
		return x.h+x.g q;

void add(int cnt,int u,int v,int w)
{
	e[cnt].next=head[u];
	e[cnt].to=v;
	e[cnt].val=w;
	head[u]=cnt;
}

void addo(int cnto,int u,int v,int w)
{
	eo[cnto].next=heado[u];
	eo[cnto].to=v;
	eo[cnto].val=w;
	heado[u]=cnto;
}

void dij(int s,int e)
{
	memset(vis,0,sizeof(vis));
	memset(dis,127,sizeof(dis));
	int mi;
	dis[e]=0;
	for(int i=1;i<=n;i++)
	{
		mi=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&dis[mi]>dis[j]) mi=j;
		vis[mi]=1;
		for(int x=heado[mi];x;x=eo[x].next)
		dis[ eo[x].to ]=min(dis[ eo[x].to ],dis[mi]+eo[x].val);
	}
}

int astar(int s,int en)
{
	anode t1,tmp;
	memset(times,0,sizeof(times));
	while(!q.empty()) q.pop();
	t1.g=t1.h=0;
	t1.p=s;
	q.push(t1);
	while(!q.empty())
	{
		t1=q.top();
		q.pop();
		times[t1.p]++;
		if(times[t1.p]<=k&&t1.h>t) return -1;
		if(times[t1.p]==k&&t1.p==en) return t1.h;
		if(times[t1.p]>k) continue;
		for(int i=head[t1.p];i;i=e[i].next)
		{
			tmp.p=e[i].to;
			tmp.g=dis[e[i].to];
			tmp.h=e[i].val+t1.h;
			q.push(tmp);
		}
	}
	return -1;
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		scanf("%d%d%d%d",&s,&en,&k,&t);
		memset(head,0,sizeof(head));
		memset(heado,0,sizeof(heado));
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add(i,x,y,z);
			addo(i,y,x,z);
		}
		dij(s,en);
		if(s==en) k++;
		int ans=astar(s,en);
		if(ans==-1||ans>t) printf("Whitesnake!\n");
		else printf("yareyaredawa\n");
	}
	return 0;
}

 

你可能感兴趣的:(A*搜索+k短路)