第k短路径的学习,及A*算法的初步认识,以及usaco牛跑步,k短路径

10 篇文章 0 订阅
8 篇文章 0 订阅

http://www.cnblogs.com/technology/archive/2011/05/26/2058842.html

把整个过程抽象来看就是这样的:

这是在有障碍的二维平面的最短的A*算法思路

好像关键在于启发式函数

把起始格添加到 "开启列表" 
do 

       寻找开启列表中F值最低的格子, 我们称它为当前格. 
       把它切换到关闭列表. 
       对当前格相邻的8格中的每一个 
          if (它不可通过 || 已经在 "关闭列表" 中) 
          { 
                什么也不做. 
           } 
          if (它不在开启列表中) 
          { 
                把它添加进 "开启列表", 把当前格作为这一格的父节点, 计算这一格的 FGH 
          if (它已经在开启列表中) 
          { 
                if (用G值为参考检查新的路径是否更好, 更低的G值意味着更好的路径) 
                    { 
                            把这一格的父节点改成当前格, 并且重新计算这一格的 GF 值. 
                    } 
} while( 目标格已经在 "开启列表", 这时候路径被找到) 
如果开启列表已经空了, 说明路径不存在.

应该有一点粗略的了解了,

F = G + H//A*算法的关键所在,直接影响它算法的效率

表示从起点 到该点的距离.

                表示从该点移动到终点 (H 有很多计算方法, 这里我们设定只可以上下左右移动).


接下来是A*与第k短路的关系

理论一:A*算法求解到的路径是最短的。

根据理论一就可以用A*路径求得最短路径,比dijkstra盲目式算法效率高。

假设用A*算法求得最短路径时,即第一次搜索到目标节点后不停止。继续启发式搜索下去,那么根据理论一可以得到第二次搜索到目标节点的路径是第二短路径。依次类推得到第k短路径。

那么A*算法的h’x)怎么设计呢?

已知h’x)与hx)越接近,时间效率越好,hx)为x到目标节点的实际最短路长。既然这样那么直接取最好值,先用dijkstra算法算出各点到目标节点的最短路径作为估价值h’x),使效率到达极大。

 

 

以前的那种写法是错误的,关建codevs的数据太弱,所以虽然过了,但还是不知道这次对不对啊

 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
int dis[1009];
struct aa
{
	int v,dis;
	aa (int v,int dis):v(v),dis(dis){};
	bool operator <(const aa &b)const
	{
		return dis>b.dis;
	}
};
struct node
{
	int v,f,g;
	node (int v,int f,int g) : v(v),f(f),g(g) {}
	bool operator <(const node &b) const 
	{
		return f>b.f;
	}
};
vector<aa> map1[1009],map2[1009];
int n,m,k,cnt[1009];
bool b[1009];
void dij()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	dis[1]=0;
	priority_queue<aa> heap;
	heap.push({1,dis[1]});
	memset(b,false,sizeof(b));
	while (!heap.empty())
	{
		int u=heap.top().v;
		heap.pop();
		if (b[u]) continue;
		b[u]=true;
		for (int i=0;i<map2[u].size();i++)
		{
			int v=map2[u][i].v;
			if (b[v]) continue;
			if (dis[v]>dis[u]+map2[u][i].dis)
			{
				dis[v]=dis[u]+map2[u][i].dis;
				heap.push({v,dis[v]});
			}
		}
	}
}
void A_star()
{
	memset(cnt,0,sizeof(cnt));
	priority_queue<node> heap;
	heap.push({n,dis[n],0}); 
	while(!heap.empty())
	{
		node b=heap.top();
		heap.pop();
		if (cnt[b.v]==k) continue;
		cnt[b.v]++;
		if (b.v==1) printf("%d\n",b.f);
		for (int i=0;i<map1[b.v].size();i++)
		{
			int v=map1[b.v][i].v;
			heap.push({v,b.g+map1[b.v][i].dis+dis[v],b.g+map1[b.v][i].dis});
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	int x,y,z;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		map1[x].push_back({y,z});
		map2[y].push_back({x,z});
	}
	dij();
	A_star();
	for (int i=cnt[1]+1;i<=k;i++) printf("-1\n");
	return 0;
}  


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值