A*和K短路
来源:互联网 发布:jsp java注释 编辑:程序博客网 时间:2024/04/29 04:18
A*
ps:作者是蒟蒻,可能有些地方是错误的,欢迎批评指正。
思想
走迷宫怎么走?用BFS就可以,但是BFS需要把所有步数<=答案的节点全部入队。
我们会发现这样遍历有很多没用的节点也入队了,能不能让这些节点不入队?这里有一个想法,就是只让最接近T(曼哈顿距离小)的节点入队,那么就变成这样了:
好像很对?其实是错的,因为迷宫可以有障碍,一旦有障碍,这个想法就会被毙掉。
黑色的是障碍,会发现S到不了T。
(其实前面都是free话)
A*的想法是,让不是最“接近T”(有了障碍物之后曼哈顿距离不一定是实际距离,所以加双引号)的节点也能入队,但是最“接近T”的节点先用来遍历,这样既可以减少入队数(虽然入队数还是可能很大,但是肯定小了很多),又可以解决之前的问题。A*也可以用来求边权不同的最短路,只要让节点能重复入队即可。
上述“接近T”被称为估价函数,视不同题目而定(比如走迷宫就可以用曼哈顿距离)格式如下:
f(n)=g(n)+h(n)
f(n)表示经过n并到达T的估计代价。
g(n)表示从S到n的实际代价。
h(n)表示从n到T的估计代价(启发式函数)。
那么f(n)越符合题意A*就越先用来遍历。
A*是一种启发式搜索,复杂度玄学,h(n)越接近实际代价,效率越高。
需要注意的是,由于f(n)只是估计代价,所以有时先到T的不一定的是真正最优的,所以要从所有到T的状态中刷出最优解才是答案(除非h(n)就是实际代价,那就没必要刷出最优解了)。
K短路
思想
最短路比较简单,但次短路就很难了,常用最短路方法无法派上用场,更恶心的是还有K短路。
其实K短路能用A*轻松解决!我们知道A*会让最“优先”的节点先遍历,所以先到T的路径常常比较短。而启发式函数h(n)我们是可以做到实际代价的:用最短路算法预处理每一个点到T的距离。这样A*每一步都是最优秀的,也就是说当第K次走到T时,就是K短路。
因为启发式函数是最好的,所以效率不错,但时间和空间复杂度还是玄学(=_=|||)。
模板
以POJ2449为例。
完全裸的K短路,只不过这道题有毛病,如果s==t不走不算一种方案,所以s==t时K要+1。
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int maxn=1000,maxm=100000,maxk=1000;int n,m,st,gl,K,tot;int E[2],lnk[2][maxn+5],nxt[2][maxm+5],son[2][maxm+5],w[2][maxm+5];int h[maxn+5],que[maxn+5];bool vis[maxn+5];struct data{ int x,g; data(int X=0,int G=0) {x=X;g=G;} bool operator < (const data &a) const {return g+h[x]>a.g+h[a.x];}};priority_queue<data> heap_s; //用优先队列来保证f小的先用来遍历bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}int readi(int &x){ int tot=0,f=1;char ch=getchar(),lst='+'; while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=getchar();} if (lst=='-') f=-f; while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=getchar(); x=tot*f; return Eoln(ch);}void Add(int id,int x,int y,int z){ son[id][++E[id]]=y;w[id][E[id]]=z; nxt[id][E[id]]=lnk[id][x];lnk[id][x]=E[id];}void Spfa() //Spfa预处理h(n){ memset(vis,0,sizeof(vis));memset(h,63,sizeof(h)); int Head=0,Tail=0;que[++Tail]=gl;vis[gl]=true;h[gl]=0; while (Head!=Tail) { int x=que[Head=(Head+1)%maxn];vis[x]=false; for (int j=lnk[1][x];j;j=nxt[1][j]) if (h[x]+w[1][j]<h[son[1][j]]) { h[son[1][j]]=h[x]+w[1][j]; if (!vis[son[1][j]]) { que[Tail=(Tail+1)%maxn]=son[1][j];vis[son[1][j]]=true; if (h[que[Tail]]<h[que[(Head+1)%maxn]]) swap(que[Tail],que[(Head+1)%maxn]); } } }}void A_star(){ while (!heap_s.empty()) heap_s.pop(); heap_s.push(data(st,0)); while (!heap_s.empty()) { data x=heap_s.top();heap_s.pop(); if (x.x==gl&&++tot==K) {printf("%d\n",x.g);break;} //第K次 for (int j=lnk[0][x.x];j;j=nxt[0][j]) heap_s.push(data(son[0][j],x.g+w[0][j])); }}int main(){ freopen("program.in","r",stdin); freopen("program.out","w",stdout); readi(n);readi(m); for (int i=1;i<=m;i++) { int x,y,z;readi(x);readi(y);readi(z); Add(0,x,y,z);Add(1,y,x,z); } readi(st);readi(gl);readi(K);if (st==gl) K++; Spfa();A_star(); if (tot<K) printf("-1\n"); return 0;}
- A*和K短路
- K短路 spfa + A*
- A*与K短路
- pku2449第K短路 最短路+A*
- poj2449 第k短路....A*+最短路
- POJ 2449 A* K短路
- POJ 2449 A* K短路
- POJ 2449 A* K短路
- POJ 2449 A* K短路
- POJ 2449 A*k短路
- POJ 2449 A*k短路
- bzoj 1598 K短路 A*
- POJ 2449 A*K短路
- POJ 2449 - A*初步+ K短路
- POJ 2449 第K短路 SPFA+A*
- POJ 2449 Dijstra + A* K短路
- POJ 2449第K短路(A*+spfa)
- poj 2449(A*求第K短路)
- Struts2之文件下载
- mysql安装
- 笔记——简单标记与标记库描述文件(TLD)
- 基于Struts2+Hibernate 基本配置
- matlab函数
- A*和K短路
- C++指针理解笔记(2)
- 【数据结构实验三】串
- 数组里面的数字的组合为某个和以及二叉树的某个路径的和为某值的全部路径
- 差分约束模板题_poj3159
- Maximum Product Subarray
- pandas学习笔记-丢弃指定轴上的项
- Typora使用指南
- Struts2的Annotation使用