A*搜索是最佳优先搜索最广为人知的形式,是一种有信息搜索策略,它的核心是一个估值函数:f(n)=g(n)+h(n),g(n)是从起始点到节点n的路径耗散,而h(n)是从节点n到目标节点的最低耗散路径的估计耗散值,因此f(n)=经过节点n的最低耗散解的估计耗散。

完备性证明:A*搜索能够找到最低耗散解的依据是一个可采纳启发式:h(n)不会高估经过节点n的实际耗散,采用可采纳启发式h(n)如果有个非最优目标节点G率先被搜索到,此时f(G) = g(G) + h(G) = g(G) > 最低耗散C*,而此时一定存在最低耗散路径上的节点n,f(n) = g(n) + h(n) <= C*,因此G不会被采纳,搜索始终会终止于一个最优解。如果一个启发式满足一致性,也就是:如果对于每个节点n和通过任何行动a生成的n的每个后继节点n',从节点n到达目标的估计号耗散值不大于从n到n'的但不耗散与从n'到达目标的耗散值之和,即h(n) <= c(n,a,n') + h(n'),类似于三角形不等式,很容易证明满足一致性的启发式就是可采纳启发式。

伪代码:

 

<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="background-color: rgb(204, 204, 204);"><span style="font-size:12px;">open ← {s};
   closed ← Ø
   while open != Ø do
       remove leftmost state from open, call it x
       if x is a goal then return success
       else
           generate children of x
           for each child c do
               if c is already on open list then
                   if c was reached by a shorter path then
                       update f(c)
               else if c is already on closed list then
                   if c was reached by a shorter path then
                        remove c from closed list
                       add c to open list and update f(c)
               else
                    assign c a heuristic value f(c)
                   add c to open list
          put x on closed list and reorder states on open by f
    return failure</span></span>
</span>


曾经写过的HDU1043八数码问题用了A*搜索:

 

 

<span style="font-family:Microsoft YaHei;font-size:14px;">
<span style="font-size:12px;">#include<iostream>
#include<queue>
#include<stack>
#include<memory.h>
#include<math.h>
#include<algorithm>

#define INF 400000
#define END 322560

using namespace std;

struct NODE
{
    int board[3][3];
    int x,y;
    int h,g;
    int state;

    bool operator < (const NODE & node) const
    {
		return (h + g) > (node.h + node.g);
    }
}sta;

int dir1[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};
char dir2[4] = {'l','r','u','d'};
int fact[9] = {1,1,2,6,24,120,720,5040,40320};
int vis[INF],pre[INF];

void init(char *);
int get_hash(const NODE &);
void aStar();
void print();
int check(const NODE &);
int val(const NODE &);

int main()
{
    char str[100];

   // freopen("Sample Input.txt","r",stdin);

    while(cin.getline(str,100))
    {
        init(str);

        if(!check(sta))
        {
            cout << "unsolvable" << endl;
        }
        else
        {
            aStar();
            print();
        }
    }

    return 0;
}

void init(char str[])
{
    int pos = 0;
    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            int pos = (3 * i + j) * 2;

            if(str[pos] == 'x')
            {
                sta.board[i][j] = 0;
                sta.x = i;
                sta.y = j;
            }
            else
            {
                sta.board[i][j] = str[pos] - '0';
            }
        }
    }

    sta.g = 0;
    sta.h = val(sta);
    sta.state = get_hash(sta);
    memset(vis,-1,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    vis[sta.state] = 1;
}

int get_hash(const NODE & node)                                        //用康托展开获得此时排列在所有排列中的位置
{
    int num[9];

    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            num[3 * i + j] = node.board[i][j];
        }
    }

    int res = 0;
    for(int i = 0;i < 9;i++)
    {
        int cnt = 0;
        for(int j = 0;j < i;j++)
        {
            if(num[j] > num[i])
            {
                cnt++;
            }
        }
        res += cnt * fact[i];
    }

    return res;
}

void aStar()
{
    priority_queue<NODE> que;
    que.push(sta);

    while(!que.empty())
    {
        NODE cur = que.top();
        que.pop();

        if(cur.state == END)
        {
            return;
        }

        for(int i = 0;i < 4;i++)
        {
            NODE next = cur;

            next.x += dir1[i][0];
            next.y += dir1[i][1];

            if(next.x < 0 || next.y < 0 || next.x > 2 || next.y > 2)
            {
                continue;
            }

            swap(next.board[cur.x][cur.y],next.board[next.x][next.y]);

            next.state = get_hash(next);

            if(vis[next.state] < 0)
            {
                vis[next.state] = i;
                pre[next.state] = cur.state;
                next.g++;
                next.h = val(next);
                que.push(next);
            }
        }
    }
}

void print()
{
    int pos = END;
    stack<char> path;

    while(pre[pos] != -1)
    {
        path.push(dir2[vis[pos]]);
        pos = pre[pos];
    }

    while(!path.empty())
    {
        cout << path.top();
        path.pop();
    }
    cout << endl;
}

int check(const NODE & node)					//剪枝
{
    int num[9];

    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            num[3 * i + j] = node.board[i][j];
        }
    }

    int cnt = 0;
    for(int i = 0;i < 9;i++)
    {
        if(num[i] == 0)
        {
            continue;
        }
        for(int j = 0;j < i;j++)
        {
            if(num[j] != 0 && num[j] > num[i])
            {
                cnt++;
            }
        }
    }

    if(cnt % 2 == 0)
        return 1;
    else
        return 0;
}


int val(const NODE & node)					//没有X时的曼哈顿距离,很明显符合一致性
{
    int sum = 0;

    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            if(node.board[i][j])
            {
                sum += abs((node.board[i][j] - 1) / 3 - i) + abs((node.board[i][j] - 1) % 3 - j);
            }
        }
    }

    return sum;

}</span>
</span>


 

 posted on 2013-06-30 14:42  莫扎特的代码  阅读(182)  评论(0编辑  收藏  举报