• HDOJ 1043 Eight(A* 搜索)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043

    思路分析:

    <1> 搜索算法: A*算法, Heuristic函数:曼哈顿距离

    <2> 剪枝技巧: 如果8数码问题中的初始状态的逆序数为奇数(除了’x’),则不存在解;否则,存在解;

    代码如下:

    #include <queue>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int MAX_N = 362880 + 100;
    int map[9];
    bool close[MAX_N];
    char dir[MAX_N], direction[] = "udlr";
    int open[MAX_N], pa[MAX_N], f[MAX_N];
    const int FACT[9] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
    const int MOVE[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
    
    struct Node
    {
        int id;
        int f, g, h;
        int flags;   // 表示该状态被松弛次数
        Node() {}
        Node(int a_id, int a_g, int a_h, int a_flags)
        {
            id = a_id, g = a_g, h = a_h, flags = a_flags;
            f = g + h;
        }
        friend bool operator<(const Node &lhs, const Node &rhs);
    };
    bool operator<(const Node &lhs, const Node &rhs)  { return lhs.f > rhs.f; }
    priority_queue<Node> find_min;
    
    int StateToCanto()
    {
        int state_num = 1;
        for (int i = 0; i < 9; ++i)
        {
            int temp = map[i] - 1;
    
            for (int j = 0; j < i; ++j)
                temp -= (map[j] < map[i]);
            state_num += temp * FACT[8 - i];
        }
        return state_num;
    }
    
    int StateToId()
    {
        int ans = 0;
    
        for (int i = 0; i < 9; ++i)
            ans = ans * 10 + map[i];
        return ans;
    }
    
    void IdToState(int num)
    {
        int i = 8;
        while (num)
        {
            map[i--] = num % 10;
            num /= 10;
        }
    }
    
    int Heuristic()
    {
        int sum = 0;
        for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
        {
            int k = i * 3 + j;
            if (map[k] == 9) continue;
            sum += abs(i - (map[k] - 1) / 3) + abs(j - (map[k] - 1) % 3);
        }
        return sum;
    }
    
    inline bool inversionNumberCheck()
    {
        int cnt = 0;
        for (int i = 0; i < 9; ++i)
        {
            if (map[i] == 9) continue;
            for (int k = i - 1; k >= 0; --k)
            {
                if (map[k] == 9) continue;
                if (map[k] > map[i])
                    cnt++;
            }
        }
        return cnt & 1;
    }
    
    void FindX(int &x, int &y)
    {
        for (int i = 0; i < 9; ++i)
        {
            if (map[i] == 9)
            {
                y = i / 3;
                x = i % 3;
                return;
            }
        }
    }
    
    int A_star()
    {
        int state_canto, state_id;
    
        state_canto = StateToCanto();
        state_id = StateToId();
        open[state_canto] += 1;
        Node start(state_id, 0, Heuristic(), open[state_canto]);
        f[state_canto] = start.f;
        find_min.push(start);
        pa[state_canto] = -1;
        dir[state_canto] = '0';
    
        if (state_id == 123456789)
            return state_canto;
    
        while (!find_min.empty())
        {
            Node parent = find_min.top();
            Node child;
            int p_x, p_y, c_x, c_y, parent_canto;
            find_min.pop();
    
            IdToState(parent.id);
            parent_canto = StateToCanto();
            if (parent.flags != open[parent_canto]) // 一个状态可能被松弛多次,检测parent是否为该状态最后一次松弛的状态
                continue;
            close[StateToCanto()] = 1; // To do
    
            FindX(p_x, p_y);
            for (int i = 0; i < 4; ++i)
            {
                int temp_swap, child_state_conto;
    
                c_x = p_x;
                c_y = p_y;
                c_x += MOVE[i][0];
                c_y += MOVE[i][1];
    
                if (c_x < 0 || c_x >= 3 || c_y < 0 || c_y >= 3)
                    continue;
                temp_swap = map[p_x + p_y * 3];
                map[p_x + p_y * 3] = map[c_x + c_y * 3];
                map[c_x + c_y * 3] = temp_swap;
                child_state_conto = StateToCanto();
    
                if (close[child_state_conto] == 1)
                {
                    temp_swap = map[p_x + p_y * 3];
                    map[p_x + p_y * 3] = map[c_x + c_y * 3];
                    map[c_x + c_y * 3] = temp_swap;
    
                    continue;
                }
    
                child.id = StateToId();
                if (child.id == 123456789)
                {
                    pa[child_state_conto] = parent_canto;
                    dir[child_state_conto] = direction[i];
                    return child_state_conto;
                }
    
                child.h = Heuristic();
                child.g = parent.g + 1;
                child.f = child.g + child.h;
                child.flags = open[child_state_conto] + 1;
                pa[child_state_conto] = parent_canto;
                dir[child_state_conto] = direction[i];
                if (open[child_state_conto] == 0 || f[child_state_conto] > child.f)
                {
                    f[child_state_conto] = child.f;
                    open[child_state_conto] = child.flags;
                    find_min.push(child);
                }
                temp_swap = map[p_x + p_y * 3];
                map[p_x + p_y * 3] = map[c_x + c_y * 3];
                map[c_x + c_y * 3] = temp_swap;
            }
        }
        return -1;
    }
    
    void Find(int i)
    {
        if (pa[i] == -1)
            return;
        else
        {
            Find(pa[i]);
            printf("%c", dir[i]);
        }
    }
    
    void PrintPath()
    {
        int end_canto;
    
        for (int i = 0; i < 9; ++i)
            map[i] = i + 1;
        end_canto = StateToCanto();
    
        Find(end_canto);
        printf("
    ");
    }
    
    int main()
    {
        int ans = 0;
    
        while (scanf("%s", &map[0]) != EOF)
        {
            map[0] = (map[0] == 'x' ? 9 : (map[0] -= '0'));
            for (int i = 1; i < 9; ++i)
            {
                scanf("%s", &map[i]);
                map[i] = (map[i] == 'x' ? 9 : (map[i] -= '0'));
            }
    
            if (inversionNumberCheck())
            {
                printf("unsolvable
    ");
                continue;
            }
            memset(open, 0, sizeof(open));
            memset(close, 0, sizeof(close));
            memset(pa, 0, sizeof(pa));
            memset(f, 0, sizeof(f));
            memset(dir, 0, sizeof(dir));
            ans = A_star();
            if (ans == -1)
                printf("unsolvable
    ");
            else
                PrintPath();
    
            while (find_min.empty())
                find_min.pop();
        }
        return 0;
    }
  • 相关阅读:
    汉字的几何中心
    输入带空格的string类型字符串 c++
    cin函数返回值
    win7玩游戏两边有黑条
    unresolved external symbol __imp__WSACleanup@0
    sizeof和strlen
    printf 函数返回值
    clone() 操作系统实验
    unsigned char 与 char
    【转】向字符数组输入空格的方法
  • 原文地址:https://www.cnblogs.com/tallisHe/p/4497954.html
Copyright © 2020-2023  润新知