嗯,因为今天考试有个状压搜索可以用A*优化,以前也做过A*的题没有AC,于是今天就打算学一下A*(Astar)……
百度第一个文章其实就不错的,地址:戳我
建议大家先去看这篇文章。
那篇文章讲的确实不错,但是例题却是坑了点,曼哈顿距离对于平面图可以卡死,但是好的启发函数对于那个图来说预处理就可以找到最短路了(宽搜),所以文章很好,例题可以考虑换一个~
下面讲一些自己的理解:启发式搜索由两部分构成,g和h,g可以理解为对前面的总结,h可以理解为对未来的期望。启发函数就是 f = g + h;
那么启发式搜索为什么快呢?因为启发式搜索由启发函数,启发函数的大小决定了这个答案的优先与否,启发函数又与自己的选择有关,所以依据题目选择一个好的启发函数是很关键的。
其他细节上边博客都讲了,这里着重讲一下POJ2449 K短路
题目链接:戳我
题目大意:给定n个点,m条边,接下来m行,每行三个数,a,b,c表示a到b又一条权值为c的边,最后一行三个数,s,t,k表示求s道t的K短路。
题目解析:
K短路,A*经典题目。
首先,g我们不用想,就是前面的点的dist,然后h应该是什么呢?曼哈顿距离?这题显然可以,因为你不知道两个点的坐标,或许你可以离散化? 233我们不用这个不科学的估价函数。
首先我们要理解,估价函数是最优估计,并不是说要求K短路就用最K优估计的估价函数。
我们可以反向建边,从终点跑最短路,这样求的一套dist,这一套dist就是每个点的估价函数,因为它是每个点到end点的最短路,所以一定最优。
这时我们想,怎么求K短呢?当求得一条到达终点的路径时我们让路径K–,第一次一定是最短路,第二次由于最优估价函数的不会再次跑到,所以第二次就是次短路(非严格次短,因为有可能两条最短路,次短长度==最短),直到第K次求得就是最短路了。
那么f怎么转移呢?f=g+h,于是求得g和h就是求f了,如果用u表示当前点,v表示边Ei连的下一个点,dist数组存的是从终点到各点的最短路,那么u点的估价函数f - dist[u] = g[u](f - h = g) g[v] = g[u] + Ei.dist(Ei.dsit表示边Ei的权值,区别于前面的dist数组,这个dist是结构体里面的),f[v] = g[v] + h[v] = g[v] + dist[v],于是转移方程:f[v] = f[u] - dist[u] + Ei.dist + dist[v];
这样当k==0时 就是K短路了。
下面贴代码一份~(本人求dist数组时用的spfa,当然有的题目用dijkstra才是更好的,本题没有刻意卡spfa)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int size = 100010;
int st,en;
struct Edge{int to,dist;}edges[size],edges2[size];
int head[size],head2[size],next[size],next2[size],tot,tot2;
void build(int f,int t,int d)
{
edges[++tot].to = t;
edges2[++tot2].to = f;
edges[tot].dist = d;
edges2[tot2].dist = d;
next[tot] = head[f];
next2[tot2] = head2[t];
head[f] = tot;
head2[t] = tot2;
}
queue <int> qq;
int dist[size];
bool vis[size];
void spfa()
{
memset(dist,63,sizeof(dist));
qq.push(en);
vis[en] = 1;
dist[en] = 0;
while(qq.size())
{
int f = qq.front();
qq.pop();
vis[f] = 0;
for(int i = head2[f];i;i = next2[i])
{
int v = edges2[i].to;
if(dist[v] > dist[f] + edges2[i].dist)
{
dist[v] = dist[f] + edges2[i].dist;
if(!vis[v])
{
vis[v] = 1;
qq.push(v);
}
}
}
}
}
struct AA{
int u,f;
bool operator < (const AA &rhs) const
{
return f > rhs.f;
}
};
priority_queue <AA> q;
int k;
//int dist2[size];
int n,m;
void Astar()
{
if(st == en) k++;
q.push((AA){st,dist[st]});
while(!q.empty())
{
AA f = q.top();
q.pop();
if(f.u == en)
{
if(!--k)
{
cout<<f.f;
return ;
}
}
for(int i = head[f.u];i;i = next[i])
{
int v = edges[i].to;
q.push((AA){v,f.f-dist[f.u]+edges[i].dist+dist[v]});
}
}
printf("-1");
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i ++)
{
int f,t,d;
scanf("%d%d%d",&f,&t,&d);
build(f,t,d);
}
scanf("%d%d%d",&st,&en,&k);
spfa();
Astar();
return 0;
}
/*
2 4
1 2 1
1 2 2
1 2 3
1 2 4
1 2 4
*/
如有问题:qq915648344,不定期在线,因为最近考试比较多~
(Orz FireStorm神犇)