【POJ2449】Remmarguts' Date(A*搜索)

来源:互联网 发布:楠楠广场舞网络一线牵 编辑:程序博客网 时间:2024/05/18 02:03

题目:我是超链接

题意:裸的K短路(s到t第k短的路)。题目大意就是给出一个图,然后给出一个起点个一个终点,求这两点间的第K短路。

题解:

如何求第k短呢?一种简单的方法是广搜,记录t出队列的次数,第k次出队的时候,就是第k短路,但这样搜索时空复杂度很高

A*是一种常见的优化,启发式搜索,它可以用公式表示为f[n]=g[n]+h[n],f[n]表示从s经节点n到t的估价函数,g[n]是在s到n的实际代价,h[n]是从n到t的最佳路径估计代价。在设计中,要保证h[n]<=n到t的实际代价(宁愿估小了遍历一遍都不要估大了),h[n]越接近真实值,速度++

算法过程:

1.反向连边,目的是求所有点到t的最短路,用dis[i]表示i到t的最短路,其实这就是A*的启发函数,显然:h(n)<= n到t的实际代价。

2.初始化状态。状态中存放当前到达的点i,fi,gi,显然,f[i]=g[i]+dis[i],存入优先队列中

3.状态转移,转移到相邻的点

4.终止条件:每个节点最多入队列k次,当t出队列k次的时候,找到解

代码:

#include <cstdio>#include <cstring>#include <queue>#define INF 1e9#define M 100005#define N 1005using namespace std;struct hh{int f,g,i;bool operator <(const hh &a)const{return a.f<f;}};int tot,nxt[M],point[N],v[M],c[M],dis[N],tot1,nxt1[M],point1[N],v1[M],c1[M],s,t,k,cnt[N];bool vis[N];void addline(int x,int y,int t){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=t;}void addline1(int x,int y,int t){++tot1; nxt1[tot1]=point1[x]; point1[x]=tot1; v1[tot1]=y; c1[tot1]=t;}void spfa(){queue <int> q;memset(vis,0,sizeof(vis));memset(dis,0x7f,sizeof(dis));dis[t]=0;q.push(t);while (!q.empty()){int now=q.front(); q.pop(); vis[now]=false;for (int i=point1[now];i;i=nxt1[i])  if (dis[v1[i]]>dis[now]+c1[i])  {  dis[v1[i]]=dis[now]+c1[i];  if (!vis[v1[i]]){q.push(v1[i]); vis[v1[i]]=true;}  }}}int A_star(int s){priority_queue<hh>q;    if (dis[s]>INF) return -1;    memset(vis,0,sizeof(vis));q.push((hh){dis[s],0,s});while (!q.empty()){hh now=q.top(),vv; q.pop();cnt[now.i]++;if (cnt[t]==k) return now.f;if (cnt[now.i]>k) continue;for (int i=point[now.i];i;i=nxt[i]){    vv.i=v[i]; vv.g=now.g+c[i]; vv.f=vv.g+dis[v[i]];  q.push(vv);}}return -1;}int main(){int m,n,i;scanf("%d%d",&n,&m);for (i=1;i<=m;i++){int x,y,t;scanf("%d%d%d",&x,&y,&t);addline1(y,x,t);addline(x,y,t);}scanf("%d%d%d",&s,&t,&k);if (s==t) k++;spfa();printf("%d",A_star(s));}


原创粉丝点击