题目链接
题解
题意
给出一个棋盘,上面分布着许多棋子,判断能否用自己的任意一个棋子在一步之内吃到指定的对面的棋子。
思路
模拟!
还是有很多可以回味的地方滴。
- 输入方面
- 可以看出棋盘的
[0, 0]
位置是在左下角的,为了方便处理我们可以倒着存图;
- 可以看出棋盘的
- 读题细节方面
- 注意
p
只能走一步而不是整个对角线; - 骑士的八个方位是不会受到除了出界之外的阻挡的;
- 国王可以走八个方位。
- 注意
代码逻辑:
存储小写字母和大写字母的位置。小写字母会被小写字母阻挡且不能到达该小写字母的位置,也会被碰到的第一个大写字母阻挡但是可以吃掉这个大写字母。通过这个判断每个小写字母所能到达的所有点。之后判断这个集合中是否包含题目给出的点即可。
AC代码
#include <bits/stdc++.h>
using namespace std;
int const N = 10;
typedef pair<int, int> P;
char ch[N][N];
set<P> big, reach, lit;
bool grid(int x, int y) {
return (x >= 0 && x < 8 && y >= 0 && y < 8) && ((lit.find(P(x, y)) == lit.end()));
}
void JudgeP(int x, int y) {
int xx = 1, yy = -1;
int X = x, Y = y;
x += xx, y += yy;
if (grid(x, y)) {
reach.insert(P(x, y));
}
x = X, y = Y;
xx = 1, yy = 1;
x += xx, y += yy;
if (grid(x, y)) {
reach.insert(P(x, y));
}
}
int f[8][2] = {
{1, -2},
{1, 2},
{-1, -2},
{-1, 2},
{2, 1},
{2, -1},
{-2, 1},
{-2, -1},
};
void JudgeC(int x, int y) {
for (auto &i : f) {
int xx = x + i[0], yy = y + i[1];
if (grid(xx, yy)) {
reach.insert(P(xx, yy));
}
}
}
void JudgeT(int x, int y) {
int xo = x, yo = y;
x -= 1;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x -= 1;
}
x = xo, y = yo;
y -= 1;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
y -= 1;
}
x = xo, y = yo;
x += 1;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x += 1;
}
x = xo, y = yo;
y += 1;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
y += 1;
}
}
void JudgeB(int x, int y) {
int xx = 1, yy = -1;
int xo = x, yo = y;
x += xx, y += yy;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x += xx, y += yy;
}
xx = -1, yy = 1;
x = xo, y = yo;
x += xx, y += yy;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x += xx, y += yy;
}
xx = -1, yy = -1;
x = xo, y = yo;
x += xx, y += yy;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x += xx, y += yy;
}
xx = 1, yy = 1;
x = xo, y = yo;
x += xx, y += yy;
while (grid(x, y)) {
reach.insert(P(x, y));
if ((big.find(P(x, y)) != big.end())) {
break;
}
x += xx, y += yy;
}
}
void JudgeR(int x, int y) {
JudgeB(x, y);
JudgeT(x, y);
}
int ff[8][2] = {
{1, 0},
{0, 1},
{0, -1},
{-1, 0},
{-1, -1},
{-1, 1},
{1, -1},
{1, 1},
};
void JudgeK(int x, int y) {
for (auto &i : ff) {
int xx = x + i[0], yy = y + i[1];
if (grid(xx, yy)) {
reach.insert(P(xx, yy));
}
}
}
int main() {
for (int i = 7; i >= 0; i--) {
scanf("%s", ch[i]);
for (int j = 0; j < 8; j++) {
if (ch[i][j] >= 'a' && ch[i][j] <= 'z') lit.insert(P(i, j));
else if (ch[i][j] != '.') {
big.insert(P(i, j));
}
}
}
for (int i = 7; i >= 0; i--) {
for (int j = 0; j < 8; j++) {
char chr = ch[i][j];
switch (chr) {
case 'p':
reach.insert(P(i, j));
JudgeP(i, j);
break;
case 'c':
JudgeC(i, j);
reach.insert(P(i, j));
break;
case 't':
JudgeT(i, j);
reach.insert(P(i, j));
break;
case 'b':
JudgeB(i, j);
reach.insert(P(i, j));
break;
case 'r':
JudgeR(i, j);
reach.insert(P(i, j));
break;
case 'k':
JudgeK(i, j);
reach.insert(P(i, j));
break;
default:
break;
}
}
}
char tmp[10];
scanf("%s", tmp);
int Y = tmp[0] - 'a', X = tmp[1] - '0' - 1;
if (reach.find(P(X, Y)) != reach.end()) {
cout << "Sim" << '\n';
} else cout << "Nao" << '\n';
return 0;
}
后记
又到了记录憨批时刻的时刻了。
读题读题读题读题!!!!
这个题是真滴让我又一次认识到了读题的重要性啊QAQ
第一次WA:这个时候代码已经大概成形,判断了一下发现棋盘的存储反了QAQ
第二次WA:误以为大小写都可以走
第三次WA:把大写字母和小写字母的处理逻辑混淆成一种,即到不了大写字母的位置。。
第四次WA:在不应该break的地方break了
第五次WA:国王可以走八个方向
第六次WA:卒一次只能走一步,我以为是一整个对角线
大概。。。就这些。。。
本来以为这题给我二十分钟还来得及,结果就很难受QAQ