1. 程式人生 > >poj 2449 Remmarguts' Date(第K短路 A*)

poj 2449 Remmarguts' Date(第K短路 A*)


(注:以下部份資料來源於網上)
所謂A*就是啟發是搜尋 說白了就是給搜尋一個順序使得搜尋更加合理減少無謂的搜尋. 如何來確定搜尋的順序?..也就是用一個值來表示 這個值為f[n]..每次搜尋取f[x]最小的拓展 那麼這個f[n]=h[n]+g[n]
其中f(n) 是節點n的估價函式,g(n)是在狀態空間中從初始節點到n節點的實際代價,h(n)是從n到目標節點最佳路徑的估計代價。在這裡主要是h(n)體現了搜尋的啟發資訊,因為g(n)是已知的。如果說詳細 點,g(n)代表了搜尋的廣度的優先趨勢。但是當h(n) >> g(n)時,可以省略g(n),而提高效率。

A*演算法的估價函式可表示為:
   
  f’(n) = g’(n) + h’(n)   
這裡,f’(n)是估價函式,g’(n)是起點到終點的最短路徑值,h’(n)n到目標的最短路經的啟發值。由於這個f’(n)其實是無法預先知道的,所以我們用前面的估價函式f(n)做近似。g(n)代替g’(n),但g(n)>=g’(n)才可(大多數情況下都是滿足的,可以不用考慮),h(n)代替h’(n),但h(n)<=h’(n)才可(這一點特別的重要)。可以證明應用這樣的估價函式是可以找到最短路徑的,也就是可採納的。我們說應用這種估價函式的最好優先演算法就是A*演算法。
下面以這道題為例,結合著理解相信你就能理解了!!

//9856K 
 297MS
#include <stdio.h>
#include <string.h>
#include <queue>
#define M 100010
#define N 1005
const int inf = 0x3f3f3f3f;
using namespace std;
struct E  //鄰接表建邊,to是下個結點,w 是權值 nxt 是下條邊的位置
{
 int to,w,nxt;
}edge[2*M];

struct data  //g 表示起點到當前點的距離,h表終點到當前點的距離
{
 int g,h;
 int to;
 bool operator < (data a) const 
 //優先佇列的排序(其實也不能這麼講) 使g+h小的在隊首
 {
 return a.h + a.g < h + g;
 }
};
int e,n,src,des,head[N],tail[N],dis[N];//head 是正向邊,tail是逆向邊 dis是des(終點)到各點的距離
void addedge (int cu,int cv,int cw)
{
 edge[e].to = cv;
 edge[e].w = cw;
 edge[e].nxt = head[cu];
 head[cu] = e ++;
 edge[e].to = cu;
 edge[e].w = cw;
 edge[e].nxt = tail[cv];
 tail[cv] = e ++;
}

void dij ()  //dijstra演算法求des到各點的距離 用於估價函式h
{
 int i,j,k;
 int vis[N];
 memset (vis,0,sizeof(vis));
 memset (dis,0x3f,sizeof(dis));
 dis[des] = 0;
 for (i = 1;i <= n;i ++)
 {
 k = -1;
 int min = inf;
 for (j = 1;j <= n;j ++)
 if (!vis[j]&&min > dis[j])
 {
 k = j;
 min = dis[j];
 }
 // if (k == -1)  //因為這裡圖肯定是連通的 可加可不加
 //  break;
 vis[k] = 1;
 for (int u = tail[k];u != -1;u = edge[u].nxt)
 {
 int v;
 v = edge[u].to;