leetcode——【逃离大迷宫】

题目

在这里插入图片描述

思路

方法一:有限步数的BFS
对于空间中一点,n个障碍点在最理想的情况下最多可包围n(n-1)/2个点,因此可得到思路:
1.对起点进行广度优先搜索,在n(n-1)/2点内找到了终点,则返回true;若遍历的点小于n(n-1)/2,则返回false;若在n(n-1)/2点内未找到终点,进行下一步;
2.对终点进行广度优先搜索,在n(n-1)/2点内找到了起点,则返回true;若遍历的点小于n(n-1)/2,则返回false;若在n(n-1)/2点内未找到起点,返回true。
方法二:离散化+BFS
对于所有点进行离散化处理,若行/列剧烈大于等于2,调整为2;若距离为1或者0,不变,即可得到规模较小的图,然后在其上进行遍历。

算法实现

方法一:

class Solution {
private:
    // 在包围圈中
    static constexpr int BLOCKED = -1;
    // 不在包围圈中
    static constexpr int VALID = 0;
    // 无论在不在包围圈中,但在n(n-1)/2步搜索中经过了target
    static constexpr int FOUND = 1;

    static constexpr int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
    static constexpr int BOUNDARY = 1000000;


public:
    bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
        if (blocked.size() < 2)
            return true;
        auto hash_fn = [fn = hash<long long>()](const pair<int, int>& o)->size_t {
            auto& x = o;
            return fn((long long)x.first << 20 | x.second);
        };
        unordered_set<pair<int, int>, decltype(hash_fn)> hash_blocked(0, hash_fn);
        for (const auto& pos : blocked)
            hash_blocked.emplace(pos[0], pos[1]);

        auto check = [&](vector<int>& start, vector<int>& finish)-> int {
            int sx = start[0], sy = start[1];
            int fx = finish[0], fy = finish[1];
            int countdown = blocked.size() * (blocked.size() - 1) / 2;
            queue<pair<int, int>> q;
            q.emplace(sx, sy);
            unordered_set<pair<int, int>, decltype(hash_fn)> visited(0, hash_fn);
            visited.emplace(sx, sy);
            while (!q.empty() && countdown > 0) {
                auto x = q.front();
                q.pop();
                for (int d = 0; d < 4; ++d) {
                    int nx = x.first + dirs[d][0], ny = x.second + dirs[d][1];
                    if (nx >= 0 && nx < BOUNDARY && ny >= 0 && ny < BOUNDARY &&
                        !hash_blocked.count({ nx, ny }) && !visited.count({ nx, ny })) {
                        if (nx == fx && ny == fy)
                            return FOUND;
                        --countdown;
                        q.emplace(nx, ny);
                        visited.emplace(nx, ny);
                    }
                }
            }
            if (countdown > 0)
                return BLOCKED;
            return VALID;
        };

        int result = check(source, target);
        if (result == FOUND)
            return true;
        else if (result == BLOCKED)
            return false;
        else {
            result = check(target, source);
            if (result == BLOCKED)
                return false;
            return true;
        }
    }
};

方法二:

class Solution {
private:
    static constexpr int BOUNDARY = 1000000;
    static constexpr int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };

public:
    bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
        if (blocked.size() < 2) {
            return true;
        }
        vector<int> rows, columns;
        for (const auto& pos : blocked) {
            rows.push_back(pos[0]);
            columns.push_back(pos[1]);
        }
        rows.push_back(source[0]);
        rows.push_back(target[0]);
        columns.push_back(source[1]);
        columns.push_back(target[1]);

        sort(rows.begin(), rows.end());
        sort(columns.begin(), columns.end());
        rows.erase(unique(rows.begin(), rows.end()), rows.end());
        columns.erase(unique(columns.begin(), columns.end()), columns.end());
        unordered_map<int, int> r_mapping, c_mapping;

        int r_id = (rows[0] == 0 ? 0 : 1);
        r_mapping[rows[0]] = r_id;
        for (int i = 1; i < rows.size(); ++i) {
            r_id += (rows[i] == rows[i - 1] + 1 ? 1 : 2);
            r_mapping[rows[i]] = r_id;
        }
        if (rows.back() != BOUNDARY - 1)
            ++r_id;

        int c_id = (columns[0] == 0 ? 0 : 1);
        c_mapping[columns[0]] = c_id;
        for (int i = 1; i < columns.size(); ++i) {
            c_id += (columns[i] == columns[i - 1] + 1 ? 1 : 2);
            c_mapping[columns[i]] = c_id;
        }
        if (columns.back() != BOUNDARY - 1) {
            ++c_id;
        }

        vector<vector<int>> grid(r_id + 1, vector<int>(c_id + 1));
        for (const auto& pos : blocked) {
            int x = pos[0], y = pos[1];
            grid[r_mapping[x]][c_mapping[y]] = 1;
        }

        int sx = r_mapping[source[0]], sy = c_mapping[source[1]];
        int tx = r_mapping[target[0]], ty = c_mapping[target[1]];

        queue<pair<int, int>> q;
        q.emplace(sx, sy);
        grid[sx][sy] = 1;
        while (!q.empty()) {
            auto x = q.front();
            q.pop();
            for (int d = 0; d < 4; ++d) {
                int nx = x.first + dirs[d][0], ny = x.second + dirs[d][1];
                if (nx >= 0 && nx <= r_id && ny >= 0 && ny <= c_id && grid[nx][ny] != 1) {
                    if (nx == tx && ny == ty) {
                        return true;
                    }
                    q.emplace(nx, ny);
                    grid[nx][ny] = 1;
                }
            }
        }
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值