HDU_1043 Eight

http://acm.hdu.edu.cn/showproblem.php?pid=1043

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

第一个A*搜索,A*是一种启发式搜索,g为已花代价,h为估计的剩余代价,而A*是根据f=g+h作为估价函数进行排列,也就是优先选择可能最优的节点进行扩展。

对于八数码问题,以下几个问题需要知道

判断有无解问题:根据逆序数直接判断有无解,对于一个八数码,依次排列之后,每次是将空位和相邻位进行调换,研究后会发现,每次调换,逆序数增幅都为偶数,也就是不改变奇偶性,所以只需要根据初始和目标状态的逆序数正负判断即可。

HASH问题:根据的是康托展开,具体证明请找网上资料

以及估价函数H:是根据与目标解的曼哈顿距离,也就是每个数字与目标位置的曼哈顿距离之和。

以了以上的基础,便可以通过A*解决八数码问题。

对于这题,实验了下,优先队列第一关键字为f,第二关键字为h,耗时2s+,第一关键字为f,第二关键字为g,耗时1s+,第一关键字为h,第二关键字为g,耗时450ms左右。在搜索过程中,加上判断是否有解,时间变化不大。POJ上0ms

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

struct Node
{
    int maze[3][3];
    int h, g;//两个估价函数
    int x, y; //空格所在的位置
    int Hash;  //HASH值
    bool operator<(const Node n1)const
    {
        return h != n1.h ? h > n1.h : g > n1.g;
    }
    bool check()
    {
        if (x >= 0 && x < 3 && y >= 0 && y < 3)
            return true;
        return false;
    }
}s,u,v,tt;
int HASH[9] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320 };
int destination = 322560;//目标情况的HASH值
int vis[400000];//判断状态已遍历,初始为-1,否则为到达这步的转向
int pre[400000];//保存路径
int way[4][2] = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } };


int get_hash(Node tmp)
{
    int a[9], k = 0;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
            a[k++] = tmp.maze[i][j];
    }
    int res = 0;
    for (int i = 0; i < 9; i++)
    {
        k = 0;
        for(int j = 0; j < i; j++)
        {
            if (a[j]>a[i])
                k++;            
        }        
        res += HASH[i] * k;
    }
    return res;
}

bool isok(Node tmp)   //求逆序对,判断是否有解
{
    int a[9], k = 0;
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
            a[k++] = tmp.maze[i][j];
    }
    int sum = 0;
    for (int i = 0; i < 9; i++)
    {
        for (int j = i + 1; j < 9; j++)
            if (a[j] && a[i] && a[i] > a[j])
                sum++;
    }
    return !(sum&1);       //由于目标解为偶数,所以状态的逆序数为偶数才行

}


int get_h(Node tmp)   //曼哈顿距离
{
    int ans = 0;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            if (tmp.maze[i][j])
                ans += abs(i - (tmp.maze[i][j] - 1) / 3) + abs(j - (tmp.maze[i][j] - 1) % 3);
    return ans;
}


void astar()
{
    priority_queueque;
    que.push(s);
    while (!que.empty())
    {
        u = que.top();
        que.pop();
        for (int i = 0; i < 4; i++)
        {
            v = u;
            v.x += way[i][0];
            v.y += way[i][1];
            if (v.check())
            {
                swap(v.maze[v.x][v.y],v.maze[u.x][u.y]);
                v.Hash = get_hash(v);
                if (vis[v.Hash] == -1 && isok(v))
                {
                    vis[v.Hash] = i;  //保存方向
                    v.g++;
                    pre[v.Hash] = u.Hash; //保存路径
                    v.h = get_h(v);
                    que.push(v);
                }
                if (v.Hash == destination)
                    return ;
            }
        }
    }
}
void print()
{
    string ans;
    ans.clear();
    int nxt = destination;
    while (pre[nxt] != -1)
    {
        switch (vis[nxt])
        {
            case 0:ans += 'r'; break;
            case 1:ans += 'l'; break;
            case 2:ans += 'd'; break;
            case 3:ans += 'u'; break;
        }
        nxt = pre[nxt];
    }
    for (int i = ans.size() - 1; i >= 0; i--)
        putchar(ans[i]);
    puts("");
}
int main()
{
    char str[100];
    while (gets(str) != NULL)
    {
        int k = 0;
        
        memset(vis,-1,sizeof(vis));
        memset(pre,-1,sizeof(pre));
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if ((str[k] <= '9'&& str[k] >= '0') || str[k] == 'x')
                {
                    if (str[k] == 'x')
                    {
                        s.maze[i][j] = 0;
                        s.x = i;
                        s.y = j;
                    }
                    else
                        s.maze[i][j] = str[k] - '0';

                }
                else
                    j--;
                k++;
            }
        }
        
        if (!isok(s))   
        {
            printf("unsolvable\n");
            continue;
        }
        s.Hash = get_hash(s);
        if (s.Hash == destination)
        {
            puts("");
            continue;
        }
        vis[s.Hash] = -2;
        s.g = 0;
        s.h = get_h(s);//puts("hello");
        astar();
        
        print();
    }
    return 0;
}

你可能感兴趣的:(搜索,A*算法)