专栏文章

题解:P11878 城堡中的皇后

P11878题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@mipydauu
此快照首次捕获于
2025/12/03 19:57
3 个月前
此快照最后确认于
2025/12/03 19:57
3 个月前
查看原文

城堡中的皇后

  • 预期难度:铜-(黄)
  • 关键词:读题、字符串处理、模拟
没啥好说的。读完题直接模拟就行了。
GPT-4o 写了一个不到一百行的 py 秒了(
彩蛋 1:本来标题是 Queen in the Rook,谐音 Queen in the rock 致敬传奇摇滚乐队皇后乐队。
彩蛋 2:第三组样例的局面 1 中,若此时轮到黑方走棋,则局面 2 为黑方的唯一着法。
局面 1 为第 45 届国际象棋奥林匹克团体赛第 7 轮中国队与印度队的比赛中,Gukesh D. 执白在第 71 回合走出 f6(兵 f6,国际象棋记谱方法中,代表兵的 P/p 可略去不写)形成的局面。实战中韦奕执黑走出了 h3?(? 代表坏棋),白棋胜势。
局面 2 为局面 1 下,黑方唯一可能的守和方式,即 Rd1+(车 d1 将军)。
彩蛋 3:第三组样例的局面 3,是初学者容易掉入的四步杀陷阱(
处理吃子逻辑时,可以利用黑方与白方大小写不同的性质,判断吃子时只需要判断 islower(u)islower(v)\operatorname{islower}(u) \oplus \operatorname{islower}(v) 是否为真即可,而不用分黑白写两个函数。
此外,注意到 Q = R + B\texttt{Q = R + B},即后的走法就是车和象的叠加,逻辑也可以简化一些。
时间复杂度为能过。
CPP
#include<bits/stdc++.h>
#define ioclear std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);
#define endl '\n'

using pii = std::pair<int, int>;

void solve()
{
    std::string s;
    std::cin >> s;
    std::vector<std::string> board(9);
    pii king, KING;
    int x = 8;
    for(auto v: s)
    {
        if(v == '/')
        {
            x--;
            continue;
        }
        if(!isdigit(v))
        {
            board[x] += v;
            continue;
        }
        for(int i = 0; i < v - '0'; i++)
            board[x] += '.';
    }
    for(int i = 1; i <= 8; i++)
        board[i] = '#' + board[i];
    for(int i = 1; i <= 8; i++)
        for(int j = 1; j <= 8; j++)
            if(board[i][j] == 'K')
                KING = {i, j};
            else if(board[i][j] == 'k')
                king = {i, j};

    auto checkRook = [&](int i, int j, std::set<pii>& s)
    {
        for(int k = i + 1; k <= 8; k++)
            if(board[k][j] == '.')
                s.insert({k, j});
            else
            {
                if(islower(board[k][j]) ^ islower(board[i][j]))
                    s.insert({k, j});
                break;
            }
        for(int k = i - 1; k >= 1; k--)
            if(board[k][j] == '.')
                s.insert({k, j});
            else
            {
                if(islower(board[k][j]) ^ islower(board[i][j]))
                    s.insert({k, j});
                break;
            }
        for(int k = j + 1; k <= 8; k++)
            if(board[i][k] == '.')
                s.insert({i, k});
            else
            {
                if(islower(board[i][k]) ^ islower(board[i][j]))
                    s.insert({i, k});
                break;
            }
        for(int k = j - 1; k >= 1; k--)
            if(board[i][k] == '.')
                s.insert({i, k});
            else
            {
                if(islower(board[i][k]) ^ islower(board[i][j]))
                    s.insert({i, k});
                break;
            }
    };

    auto checkBishop = [&](int i, int j, std::set<pii>& s)
    {
        for(int ii = i + 1, jj = j + 1; ii <= 8 && jj <= 8; ii++, jj++)
            if(board[ii][jj] == '.')
                s.insert({ii, jj});
            else
            {
                if(islower(board[ii][jj]) ^ islower(board[i][j]))
                    s.insert({ii, jj});
                break;
            }
        for(int ii = i - 1, jj = j - 1; ii >= 1 && jj >= 1; ii--, jj--)
            if(board[ii][jj] == '.')
                s.insert({ii, jj});
            else
            {
                if(islower(board[ii][jj]) ^ islower(board[i][j]))
                    s.insert({ii, jj});
                break;
            }
        for(int ii = i + 1, jj = j - 1; ii <= 8 && jj >= 1; ii++, jj--)
            if(board[ii][jj] == '.')
                s.insert({ii, jj});
            else
            {
                if(islower(board[ii][jj]) ^ islower(board[i][j]))
                    s.insert({ii, jj});
                break;
            }
        for(int ii = i - 1, jj = j + 1; ii >= 1 && jj <= 8; ii--, jj++)
            if(board[ii][jj] == '.')
                s.insert({ii, jj});
            else
            {
                if(islower(board[ii][jj]) ^ islower(board[i][j]))
                    s.insert({ii, jj});
                break;
            }
    };

    auto checkKing = [&](int i, int j, std::set<pii>& s)
    {
        std::vector<pii> pos = {{i + 1, j}, {i - 1, j}, {i, j + 1}, {i, j - 1}, {i + 1, j + 1}, {i - 1, j - 1}, {i + 1, j - 1}, {i - 1, j + 1}};
        for(auto [x, y]: pos)
        {
            if(x < 1 || x > 8 || y < 1 || y > 8)
                continue;
            if(board[x][y] == '.' || (islower(board[i][j]) ^ islower(board[x][y])))
                s.insert({x, y});
        }
    };

    auto checkKnight = [&](int i, int j, std::set<pii>& s)
    {
        std::vector<pii> pos = {{i - 1, j + 2}, {i + 1, j + 2}, {i - 2, j + 1}, {i - 2, j - 1}, {i + 2, j + 1}, {i + 2, j - 1}, {i - 1, j - 2}, {i + 1, j - 2}};
        for(auto [x, y]: pos)
        {
            if(x < 1 || x > 8 || y < 1 || y > 8)
                continue;
            if(board[x][y] == '.' || (islower(board[i][j]) ^ islower(board[x][y])))
                s.insert({x, y});
        }
    };

    auto checkPawn = [&](int i, int j, std::set<pii>& s)
    {
        if(isupper(board[i][j]))
        {
            std::vector<pii> pos = {{i + 1, j - 1}, {i + 1, j + 1}};
            for(auto [x, y]: pos)
            {
                if(x < 1 || x > 8 || y < 1 || y > 8)
                    continue;
                if(board[x][y] == '.' || islower(board[x][y]))
                    s.insert({x, y});
            }
        }
        if(islower(board[i][j]))
        {
            std::vector<pii> pos = {{i - 1, j - 1}, {i - 1, j + 1}};
            for(auto [x, y]: pos)
            {
                if(x < 1 || x > 8 || y < 1 || y > 8)
                    continue;
                if(board[x][y] == '.' || isupper(board[x][y]))
                    s.insert({x, y});
            }
        }
    };


    auto checkWhite = [&]() -> bool
    {
        std::set<pii> s;
        for(int i = 1; i <= 8; i++)
            for(int j = 1; j <= 8; j++)
            {
                if(board[i][j] == 'Q')
                {
                    checkRook(i, j, s);
                    checkBishop(i, j, s);
                }
                if(board[i][j] == 'R')
                    checkRook(i, j, s);
                if(board[i][j] == 'B')
                    checkBishop(i, j, s);
                if(board[i][j] == 'N')
                    checkKnight(i, j, s);
                if(board[i][j] == 'K')
                    checkKing(i, j, s);
                if(board[i][j] == 'P')
                    checkPawn(i, j, s);
            }
        return s.count(king);
    };
    
    auto checkBlack = [&]() -> bool
    {
        std::set<pii> s;
        for(int i = 1; i <= 8; i++)
            for(int j = 1; j <= 8; j++)
            {
                if(board[i][j] == 'q')
                {
                    checkRook(i, j, s);
                    checkBishop(i, j, s);
                }
                if(board[i][j] == 'r')
                    checkRook(i, j, s);
                if(board[i][j] == 'b')
                    checkBishop(i, j, s);
                if(board[i][j] == 'n')
                    checkKnight(i, j, s);
                if(board[i][j] == 'k')
                    checkKing(i, j, s);
                if(board[i][j] == 'p')
                    checkPawn(i, j, s);
            }
        return s.count(KING);
    };

    if(checkWhite())
        std::cout << "CHECK" << endl;
    else if(checkBlack())
        std::cout << "check" << endl;
    else
        std::cout << "none" << endl;
}

int main()
{
    #ifdef ONLINE_JUDGE
    ioclear;
    #endif

    int t = 1;
    std::cin >> t;
    while(t--)
        solve();
}
PY
def parse_fen(fen):
    # 解析FEN字符串,返回一个8x8的棋盘矩阵
    board = []
    rows = fen.split(' ')[0].split('/')
    for row in rows:
        board_row = []
        for char in row:
            if char.isdigit():
                # 如果是数字,说明有这么多空格
                board_row.extend(['.'] * int(char))
            else:
                # 否则是棋子
                board_row.append(char)
        board.append(board_row)
    return board
 
def find_king(board, color):
    # 找到指定颜色的国王的位置
    king = 'K' if color == 'white' else 'k'
    for i in range(8):
        for j in range(8):
            if board[i][j] == king:
                return (i, j)
    return None
 
def is_attacked(board, row, col, attacker_color):
    # 判断(row, col)位置是否被指定颜色的棋子攻击
    directions = {
        'R': [(1, 0), (-1, 0), (0, 1), (0, -1)],  # 车的移动方向
        'B': [(1, 1), (-1, -1), (1, -1), (-1, 1)],  # 象的移动方向
        'Q': [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)],  # 后的移动方向
        'N': [(2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, 2), (-1, -2)]  # 马的移动方向
    }
 
    for piece, dirs in directions.items():
        # 检查车、象、后、马的攻击
        for dr, dc in dirs:
            r, c = row + dr, col + dc
            while 0 <= r < 8 and 0 <= c < 8:
                if board[r][c] != '.':
                    if (attacker_color == 'black' and board[r][c] == piece.lower()) or \
                       (attacker_color == 'white' and board[r][c] == piece.upper()):
                        return True
                    break
                if piece in 'Nn':  # 马只跳一步
                    break
                r += dr
                c += dc
 
    # 检查兵的攻击(兵只能向对角线进攻)
    if attacker_color == 'black':
        if row > 0 and col > 0 and board[row - 1][col - 1] == 'p':
            return True
        if row > 0 and col < 7 and board[row - 1][col + 1] == 'p':
            return True
    else:
        if row < 7 and col > 0 and board[row + 1][col - 1] == 'P':
            return True
        if row < 7 and col < 7 and board[row + 1][col + 1] == 'P':
            return True
 
    # 检查国王的攻击(国王只移动一步)
    king = 'k' if attacker_color == 'black' else 'K'
    for dr in [-1, 0, 1]:
        for dc in [-1, 0, 1]:
            if 0 <= row + dr < 8 and 0 <= col + dc < 8:
                if board[row + dr][col + dc] == king:
                    return True
 
    return False
 
def is_check(fen):
    board = parse_fen(fen)
 
    # 找到白王和黑王的位置
    white_king_pos = find_king(board, 'white')
    black_king_pos = find_king(board, 'black')
 
    # 检查白王是否被黑方棋子攻击
    if is_attacked(board, white_king_pos[0], white_king_pos[1], 'black'):
        return "check"
    
    # 检查黑王是否被白方棋子攻击
    if is_attacked(board, black_king_pos[0], black_king_pos[1], 'white'):
        return "CHECK"
    
    return "none"
 
# 示例FEN
t = int(input())
for _ in range(t):
    fen = input()
    result = is_check(fen)
    print(result)

评论

3 条评论,欢迎与作者交流。

正在加载评论...