题解:P11878 城堡中的皇后
城堡中的皇后
- 预期难度:铜-(黄)
- 关键词:
读题、字符串处理、模拟
没啥好说的。读完题直接模拟就行了。
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,是初学者容易掉入的四步杀陷阱(
处理吃子逻辑时,可以利用黑方与白方大小写不同的性质,判断吃子时只需要判断
此外,注意到
时间复杂度为能过。
#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();
}
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)