周一

n皇后II
好久不写了,脑袋木掉了。
总之就是回溯+状态压缩(位运算),用三个比特集合存储横行、左斜行、右斜行的情况,然后按列扫描并回溯就好。
用到了std::bitset,这个感觉还算有点用。

class Solution {
public:
    std::bitset<10>col{0};
    std::bitset<20>diag1{0}, diag2{0};
    int cnt{0};
    void queen(int row, int n){
        if(row == n){
        // std::cout<<"row = "<<row<<'\n';
        // std::cout<<col.to_string()<<'\n';
        // std::cout<<diag1.to_string()<<'\n';
        // std::cout<<diag2.to_string()<<'\n';
            cnt++;
            return;
        }
        for(int i = 0; i < n; i++){
        // 左斜行和右斜行的idx搞对就好
            if(!col[i] && !diag1[i + row] && !diag2[i + n - 1 - row]){
                col[i] = 1;
                diag1[i + row] = 1;
                diag2[i + n - 1 - row] = 1;
                queen(row + 1, n);
                col[i] = 0;
                diag1[i + row] = 0;
                diag2[i + n - 1 - row] = 0;
            }
        }
    }
    int totalNQueens(int n) {
        queen(0, n);
        return cnt;
    }
};

周二

感冒了,正好出了一道eazy,签个到算了
3274. 检查棋盘方格颜色是否相同

class Solution {
public:
    bool checkTwoChessboards(string coordinate1, string coordinate2) {
        return !((coordinate1[0] - 'a' + coordinate1[1] - '1' 
                + coordinate2[0] - 'a' + coordinate2[1] - '1') % 2);
    }
};

周三

2056. 棋盘上有效移动组合的数目
hard,头痛牙痛,脑袋蒙蒙,知道要用回溯/搜索,但就是搞不对,感觉是对数据结构的组织不太好。下面是别人的解法:

struct Move {
    int x0, y0; // 起点
    int dx, dy; // 移动方向
    int step;   // 移动次数
};

class Solution {
    vector<pair<int, int>> DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {1, 1}, {-1, 1}, {-1, -1}, {1, -1}}; // 上下左右 + 斜向
    unordered_map<char, vector<pair<int, int>>> PIECE_DIRS = {
        {'r', {DIRS.begin(), DIRS.begin() + 4}},
        {'b', {DIRS.begin() + 4, DIRS.end()}},
        {'q', DIRS},
    };

    // 计算位于 (x0,y0) 的棋子在 dirs 这些方向上的所有合法移动
    vector<Move> generate_moves(int x0, int y0, vector<pair<int, int>>& dirs) {
        const int SIZE = 8;
        vector<Move> moves = {{x0, y0, 0, 0, 0}}; // 原地不动
        for (auto [dx, dy] : dirs) {
            // 往 d 方向走 1,2,3,... 步
            int x = x0 + dx, y = y0 + dy;
            for (int step = 1; 0 < x && x <= SIZE && 0 < y && y <= SIZE; step++) {
                moves.emplace_back(x0, y0, dx, dy, step);
                x += dx;
                y += dy;
            }
        }
        return moves;
    }

    // 判断两个移动是否合法,即不存在同一时刻两个棋子重叠的情况
    bool is_valid(Move& m1, Move& m2) {
        int x1 = m1.x0, y1 = m1.y0;
        int x2 = m2.x0, y2 = m2.y0;
        for (int i = 0; i < max(m1.step, m2.step); i++) {
            // 每一秒走一步
            if (i < m1.step) {
                x1 += m1.dx;
                y1 += m1.dy;
            }
            if (i < m2.step) {
                x2 += m2.dx;
                y2 += m2.dy;
            }
            if (x1 == x2 && y1 == y2) { // 重叠
                return false;
            }
        }
        return true;
    }

public:
    int countCombinations(vector<string>& pieces, vector<vector<int>>& positions) {
        int n = pieces.size();
        // 预处理所有合法移动
        vector<vector<Move>> all_moves(n);
        for (int i = 0; i < n; i++) {
            all_moves[i] = generate_moves(positions[i][0], positions[i][1], PIECE_DIRS[pieces[i][0]]);
        }

        vector<Move> path(n); // 注意 path 的长度是固定的
        int ans = 0;
        auto dfs = [&](auto& dfs, int i) -> void {
            if (i == n) {
                ans++;
                return;
            }
            // 枚举当前棋子的所有合法移动
            for (Move& move1 : all_moves[i]) {
                // 判断合法移动 move1 是否有效
                bool ok = true;
                for (int j = 0; j < i; j++) {
                    if (!is_valid(move1, path[j])) {
                        ok = false;
                        break;
                    }
                }
                if (ok) {
                    path[i] = move1; // 直接覆盖,无需恢复现场
                    dfs(dfs, i + 1); // 枚举后续棋子的所有合法移动组合
                }
            }
        };
        dfs(dfs, 0);
        return ans;
    }
};

周四

3001. 捕获黑皇后需要的最少移动次数
模拟题,搞对就行,没啥特别的,但要注意浮点数精度

class Solution {
public:
    int minMovesToCaptureTheQueen(int a, int b, int c, int d, int e, int f) {
        if((c + d + e + f) % 2 == 1){
            //cout << "白色象和黑皇后不在同一种颜色的格子里,只能使用车来捕获\n";
            if(a == e || b == f){
                //cout << "车和皇后在同一行/同一列\n";
                if(a == c && a == e && (d - b) * (d - f) < 0){
                    //cout << "象在车和皇后中间\n";
                    return 2;
                }else if(b == d && b == f && (c - a) * (c - e) < 0){
                    //cout << "象在车和皇后中间\n";
                    return 2;
                }
                return 1;
            }
            //cout << "不在同一行/同一列\n";
            return 2;
        }
        // 可能是车,可能是象
        if(a == e || b == f){
            //cout << "车和皇后在同一行/同一列\n";
            if(a == c && a == e && (d - b) * (d - f) < 0){
                //cout << "象在车和皇后中间\n";
                return 2;
            }else if(b == d && b == f && (c - a) * (c - e) < 0){
                //cout << "象在车和皇后中间\n";
                return 2;
            }
            return 1;
        }
        if(float k = e == c ? 0 : float(f - d) / (e - c);
                abs(abs(k) - 1) < 0.0001){
            //cout << "象和皇后在同一个斜线\n";
            float k1 = float(f - b) / (e - a);
            if(abs(k - k1) < 0.0001){
                //cout << "斜率相同\n";
                if((b - d) * (b - f) < 0){
                    //cout << "车在象和皇后中间\n";
                    return 2;
                }
            }
            return 1;
        }
        //cout << "普通情况\n";
        return 2;
    }
};

周五

999. 可以被一步捕获的棋子数
easy,抄答案了

class Solution {
public:
    int numRookCaptures(vector<vector<char>>& board) {
        int cnt = 0, st = 0, ed = 0;
        int dx[4] = {0, 1, 0, -1};
        int dy[4] = {1, 0, -1, 0};
        for (int i = 0; i < 8; ++i) {
            for (int j = 0; j < 8; ++j) {
                if (board[i][j] == 'R') {
                    st = i;
                    ed = j;
                    break;
                }
            }
        }
        for (int i = 0; i < 4; ++i) {
            for (int step = 0;; ++step) {
                int tx = st + step * dx[i];
                int ty = ed + step * dy[i];
                if (tx < 0 || tx >= 8 || ty < 0 || ty >= 8 || board[tx][ty] == 'B') {
                    break;
                }
                if (board[tx][ty] == 'p') {
                    cnt++;
                    break;
                }
            }
        }
        return cnt;
    }
};

周六

688. 骑士在棋盘上的概率
mid,偷懒了,暴力搜索没写出来,看了答案,挺普通的dp

class Solution {
public:
    vector<vector<int>> dirs = {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}};
    double knightProbability(int n, int k, int row, int column) {
        vector<vector<vector<double>>> dp(k + 1, vector<vector<double>>(n, vector<double>(n)));
        for (int step = 0; step <= k; step++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (step == 0) { dp[step][i][j] = 1; } 
                    else {
                        for (auto & dir : dirs) {
                            int ni = i + dir[0], nj = j + dir[1];
                            if (ni >= 0 && ni < n && nj >= 0 && nj < n) {
                                dp[step][i][j] += dp[step - 1][ni][nj] / 8;
                            }
                        }
                    }
                }
            }
        }
        return dp[k][row][column];
    }
};
请随意转载