• HDOJ 1429 胜利大逃亡(续) (bfs+状态压缩)


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

    思路分析:题目要求找出最短的逃亡路径,但是与一般的问题不同,该问题增加了门与钥匙约束条件;

    考虑一般的搜索问题的解答思路:

    搜索算法即在解空间中搜索满足要求的答案,可以看做一棵不断生长的状态树,状态之间不断扩展出新的状态,直到找出所需要的状态,即答案;

    <1>定义状态:对于该问题,由于存在门与锁的约束条件,所以状态应该包括3个元素,即人所在的坐标 x 和 y 以及含有锁的种类;

    <2>剪枝方法:因为在bfs搜索中会出现相同的状态,所以需要判重,使用vis数组即可;另外需要根据下一状态的位置已经该位置的字符判断能否拓展;

    <3>状态压缩:对于拥有的钥匙进行状态压缩,使用一个10个位进行标记是否拥有钥匙 A~J ,将该10个bit压缩为一个整数即为状态压缩;

    <4>位运算获得锁X与判断是否拥有锁X: 对于获得锁,可以使用或运算使第i个位为1,;判断是否拥有锁,可以使用与运算判断;

    代码如下:

    #include <queue>
    #include <iostream>
    using namespace std;
    
    #define MAX_N  21
    #define KEY_N  (1 << 10)
    bool vis[MAX_N][MAX_N][KEY_N];
    char map[MAX_N][MAX_N];
    int dir[4][2] = {0, -1, 0, 1, -1, 0, 1, 0};
    int map_x, map_y;
    
    struct State
    {
        int x, y;
        int step, key_value;
        State() {}
        State(int i, int j, int s, int k){ x = i; y = j; step = s; key_value = k; }
    };
    
    int GetKey(int key, char ch) { return key | (1 << (ch - 'a')); }
    bool OpenDoor(int key, char ch) { return key & (1 << (ch - 'A')); }
    
    int Bfs(int x, int y, int game_times)
    {
        queue<State> state_queue;
        State start(x, y, 0, 0);
    
        vis[x][y][0] = true;
        state_queue.push(start);
        while (!state_queue.empty())
        {
            State now = state_queue.front();
            State next;
            state_queue.pop();
    
            if (now.step + 1 >= game_times)
                continue;
            for (int i = 0; i < 4; ++i)
            {
                int n_x, n_y, n_step, n_key_value;
    
                n_x = now.x + dir[i][0];
                n_y = now.y + dir[i][1];
                n_step = now.step + 1;
                n_key_value = now.key_value;
                if (n_x < 0 || n_x >= map_x || n_y < 0 || n_y >= map_y)
                    continue;
                if (vis[n_x][n_y][n_key_value] || map[n_x][n_y] == '*')
                    continue;
                if (map[n_x][n_y] == '^')
                    return n_step;
                if ('a' <= map[n_x][n_y] && map[n_x][n_y] <= 'z')
                {
                    n_key_value = GetKey(n_key_value, map[n_x][n_y]);
                    if (vis[n_x][n_y][n_key_value])
                        continue;
                }
                if ('A' <= map[n_x][n_y] && map[n_x][n_y] <= 'Z')
                {
                    if (!OpenDoor(n_key_value, map[n_x][n_y]))
                        continue;
                }
                next.x = n_x;
                next.y = n_y;
                next.step = n_step;
                next.key_value = n_key_value;
                state_queue.push(next);
                vis[n_x][n_y][n_key_value] = true;
            }
        }
        return -1;
    }
    
    
    int main()
    {
        int game_times;
        int start_x, start_y;
    
        while (scanf("%d %d %d
    ", &map_x, &map_y, &game_times) != EOF)
        {
            int ans = 0;
    
            memset(map, 0, sizeof(map));
            memset(vis, 0, sizeof(vis));
            for (int i = 0; i < map_x; ++i)
            {
                scanf("%s", &map[i]);
                for (int j = 0; j < map_y; ++j)
                {
                    if (map[i][j] == '@')
                        start_x = i, start_y = j;
                }
            }
    
            ans = Bfs(start_x, start_y, game_times);
            if (ans == -1)
                printf("-1
    ");
            else
                printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    迭代器与生成器
    11.30
    函数及装饰器
    C#For循环
    C#变量与数据类型
    C#输入输出
    JDK10新特性--var
    idea插件Lombok使用
    NodeJs操作文件-写入、修改、删除、追加、读取文件内容、判断文件是否存在
    mongodb多条件分页查询(mongoTemplate分页查询)
  • 原文地址:https://www.cnblogs.com/tallisHe/p/4506506.html
Copyright © 2020-2023  润新知