POJ 2449 - A*初步+ K短路

本文介绍A*算法的基本原理及其在寻找K短路径问题中的应用,详细讲解了如何结合BFS与A*算法来高效求解,并提供了具体实现代码。

原文地址: http://blog.youkuaiyun.com/kk303/article/details/6953943

原以为A*会很难懂~~~结果狐狸大大一口气就给我讲懂了A*和K短路的求法.....

    所谓A*就是启发是搜索..说白了就是给BFS搜索一个顺序使得搜索更加合理减少无谓的搜索..如何来确定搜索的顺序?..也就是用一个值来表示这个值为f[x]..每次搜索取f[x]最小的拓展...那么这个f[x]=h[x]+g[x]其中这个h[x]就是当前搜索时的代价..如求K段路这个就是前一个点的h[x']+边的长度...而g[x]是一个估价函数..估价函数要小于是对当前点到目标的代价的估计..这个估计必须小于等于实际值~~否则会出错...A*的关键也就是构造g[x]..

    而这里要说的求K短路一种方法..就是用BFS+A*来搜索的过程...g[x]的设定为到这个点到目标点的最短路径...显然其实小于等于实际值的...h[x]就是搜索到这个点的代价..用一个优先队列来做..每次取出h[x]+g[x]最小的点来拓展...拓展也就是通过这点来更新其能直接经过一条边到达的点..这里做好一个新点就丢进优先队列里去..反正总会从对首弹出h[x]+g[x]最小的点..可以想一下...如果当前取出的优先队列头是一个点e并且是第一次取出h..那么就找到了一条从源点到h的最短路径..这里其实很djikstra的感觉差不多..如果第二次在对头取出了e..则是找到了一条从源点到h的第二短路径..依次类推..第几次从对头弹出e..则找到了从源点到e的第几短路径..

    那要是本身就不存在K短路呢??那就是e拓展不到K但是其他点很有可能一直打圈圈无限下去...这里就要用个条件来判断一下...首先在找某个点作为优先队列头出现了几次就用了一个计数器times[]..所求的点times[e]==k就代表得到了解..如果当前想拓展的点times[]>k就没必要拓展了..因为这个点已经是求到k+1短路了..从这个点继续往下搜肯定得到的是大于等于k+1短路的路径...就像1->2有3条路..2->3有2条路..那1->3有6条路的概念差不多..没必要对其进行拓展了..

    还有一点要特别注意的就是题目要求必须要走..也就是s==e时..k++....

    补充说一下STL的priority_queue 也就是STL就已经有一个优先队列了..像sort一样的可以直接使用..

    声明   #include<queue>

    定义   priority_queue<类型> 变量名 

    但注意的是若是对结构体用..则需要在结构体中对 < 进行重载...如这道题的struct就应该写成这样:

[cpp]  view plain  copy
  1. struct node  
  2. {  
  3.      int p,g,h;  
  4.      bool operator < (node a) const  
  5.      {   
  6.           return a.g+a.h<g+h;  
  7.      }       
  8. };   
      这样用 priority_queue就能按需求来进行优先级了...插入时用push..取队首用top..再弹出pop...判空empty...啥啥的..和一般的queue一样...很好使...



Program:

[cpp]  view plain  copy
  1. #include<iostream>  
  2. #include<queue>  
  3. #define MAXN 1001  
  4. using namespace std;  
  5. struct node  
  6. {  
  7.      int p,g,h;  
  8.      bool operator < (node a) const  
  9.      {   
  10.           return a.g+a.h<g+h;  
  11.      }       
  12. };  
  13. struct node1  
  14. {  
  15.      int x,y,w,next;        
  16. }line[MAXN*100],line1[MAXN*100];  
  17. int n,m,i,link[MAXN],link1[MAXN],g[MAXN],s,e,k;  
  18. bool used[MAXN];  
  19. priority_queue<node> myqueue;   
  20. void djikstra()  
  21. {   
  22.      int i,k,p;  
  23.      memset(used,0,sizeof(used));  
  24.      memset(g,0x7F,sizeof(g));   
  25.      g[e]=0;  
  26.      for (p=1;p<=n;p++)  
  27.      {  
  28.           k=0;  
  29.           for (i=1;i<=n;i++)   
  30.             if (!used[i] && (!k || g[i]<g[k]))  
  31.               k=i;  
  32.           used[k]=true;  
  33.           k=link1[k];  
  34.           while (k)  
  35.           {  
  36.                if (g[line1[k].y]>g[line1[k].x]+line1[k].w)  
  37.                    g[line1[k].y]=g[line1[k].x]+line1[k].w;  
  38.                k=line1[k].next;                 
  39.           }  
  40.      }  
  41.      return ;      
  42. }  
  43. int Astar()  
  44. {  
  45.      int t,times[MAXN];  
  46.      node h,temp;  
  47.      while (!myqueue.empty()) myqueue.pop();  
  48.      memset(times,0,sizeof(times));   
  49.      h.p=s; h.g=0; h.h=0; myqueue.push(h);  
  50.      while (!myqueue.empty())  
  51.      {  
  52.            h=myqueue.top();  
  53.            myqueue.pop();  
  54.            times[h.p]++;   
  55.            if (times[h.p]==k && h.p==e) return h.h+h.g;     
  56.            if (times[h.p]>k) continue;       
  57.            t=link[h.p];  
  58.            while (t)  
  59.            {   
  60.                  temp.h=h.h+line[t].w;  
  61.                  temp.g=g[line[t].y];  
  62.                  temp.p=line[t].y;  
  63.                  myqueue.push(temp);  
  64.                  t=line[t].next;  
  65.            }   
  66.      }  
  67.      return -1;     
  68. }  
  69. int main()  
  70. {   
  71.      scanf("%d%d",&n,&m);  
  72.      memset(link,0,sizeof(link));   
  73.      memset(link1,0,sizeof(link1));  
  74.      for (i=1;i<=m;i++)  
  75.      {           
  76.           scanf("%d%d%d",&line[i].x,&line[i].y,&line[i].w);  
  77.           line[i].next=link[line[i].x]; link[line[i].x]=i;     
  78.           line1[i].x=line[i].y; line1[i].y=line[i].x; line1[i].w=line[i].w;  
  79.           line1[i].next=link1[line1[i].x]; link1[line1[i].x]=i;      
  80.      }  
  81.      scanf("%d%d%d",&s,&e,&k);  
  82.      if (s==e) k++;  
  83.      djikstra();  
  84.      printf("%d\n",Astar());   
  85.      return 0;     
  86. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值