#include
#include
using namespace std;
struct chess
{
char t;
int x, y;
};
int n;
chess c[8];
chess gnr;
char tab0[11][11], tab[11][11];//[10][9]
//在check函数中有j/2 所以mov和movh中的坐标需要对应
int mov[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
int movh[8][2] = { {-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1} };
bool legal(int x, int y)
{
return 1 <= x && x <= 3 && 4 <= y && y <= 6;
}
int cnt(chess p1, chess p2)
{
int cnt = 0;
if (p1.x == p2.x)
{
int add = p1.y < p2.y ? 1 : -1;
for (int i = p1.y + add; i != p2.y; i+=add)
{
if (tab[p1.x][i] != '0')cnt++;
}
}
else if (p1.y == p2.y)
{
int add = p1.x < p2.x ? 1 : -1;
for (int i = p1.x + add; i != p2.x; i += add)
{
if (tab[i][p1.y] != '0')cnt++;
}
}
else
cnt = -1;
return cnt;
}
bool check()
{
for (int i = 1; i <= n; i++)
{
if (c[i].x == c[0].x && c[i].y == c[0].y)continue;
if (c[i].t == 'R' || c[i].t == 'G')
{
if (cnt(c[i], c[0]) == 0)return false;
}
if (c[i].t == 'C')
{
if (cnt(c[i], c[0]) == 1)return false;
}
if (c[i].t == 'H')
{
for (int j = 0; j < 8; j++)
{
if (c[i].x + movh[j][0] == c[0].x && c[i].y + movh[j][1] == c[0].y
&& tab[c[i].x + mov[j / 2][0]][c[i].y + mov[j / 2][1]] == '0')
return false;
}
}
}
return true;
}
int main()
{
while (cin >> n >> gnr.x >> gnr.y && (n || gnr.x || gnr.y))
{
memset(tab0, '0', sizeof(tab0));
tab0[gnr.x][gnr.y] = '1';
for (int i = 1; i <= n; i++)
{
cin >> c[i].t >> c[i].x >> c[i].y;
tab0[c[i].x][c[i].y] = c[i].t;
}
bool res = true;
for (int i = 0; i < 4; i++)
{
memcpy(tab, tab0, sizeof(tab0));
c[0].x = gnr.x + mov[i][0];
c[0].y = gnr.y + mov[i][1];
if (!legal(c[0].x, c[0].y))continue;
tab[c[0].x][c[0].y] = '1';
tab[gnr.x][gnr.y] = '0';
if (check())
{
res = false;
break;
}
}
if (res)puts("YES");
else puts("NO");
}
return 0;
}
参考自https://blog.csdn.net/thudaliangrx/article/details/50700688?locationNum=2&fps=1#t9
虽说是参考但是几乎没改动 只是加上了自己的很多理解
这位博主感觉还是蛮厉害的 反正在我看来如此啦~(可能也是因为菜什么的)
这道题涉及了很多象棋方面的知识
各类棋子的走法姑且不论 最让我头疼的是蹩马腿这事儿
还好只有炮(C)、车(R)、马(H)、还有飞将(G)这么几种情况
当然 还有如同原文作者所言 还有“黑将吃红子”这种情况。
题意:象棋残局,黑方仅剩一枚将,红方剩余n枚棋子。
思路:模拟红方和黑方的走动,并判断是否黑方不管怎么走都会被将死 那么 定义函数来实现这个过程即可。
然后我打算一点点把这段程序讲明白(小黄鸭大法)
1.结构体chess
struct chess
{
char t;
int x, y;
};
t为类型 x,y 都是坐标。
因为象棋分红黑两方 所以为了方便红方用一个结构体数组是再好不过的了
2.主体部分
int main()
{
while (cin >> n >> gnr.x >> gnr.y && (n || gnr.x || gnr.y))//输入n 和 gnr的坐标
{
memset(tab0, '0', sizeof(tab0));
tab0[gnr.x][gnr.y] = '1';
for (int i = 1; i <= n; i++)
{
cin >> c[i].t >> c[i].x >> c[i].y;
tab0[c[i].x][c[i].y] = c[i].t;
}
bool res = true;
for (int i = 0; i < 4; i++)
{
memcpy(tab, tab0, sizeof(tab0));
c[0].x = gnr.x + mov[i][0];
c[0].y = gnr.y + mov[i][1];
if (!legal(c[0].x, c[0].y))continue;
tab[c[0].x][c[0].y] = '1';
tab[gnr.x][gnr.y] = '0';
if (check())
{
res = false;
break;
}
}
if (res)puts("YES");
else puts("NO");
}
return 0;
}
我们首先要输入的是红色棋子的数量和黑将的位置,那么黑将接下来将移动,会怎么移,上下左右,而且不可以出那个九个点,这也是legal的作用,用于判断黑将是否在九个点上,而除了tab还需要定义一个tab0,一个原因是方便在接下来假设黑将走动的各种情况后将黑将回复原位,令一个原因是防止黑将吃掉红子。
check就是检查有没有被将死的情况 如果被将死了 那么返回false 如果有任意一种方法可以是黑将这一回合不死 那么就会输入YES 所以我们这里的check就得返回true 然后直接break
c[0]是移动后的黑将的坐标,其实令外定义一个chess也可以。
2.check函数
bool check()
{
for (int i = 1; i <= n; i++)
{
if (c[i].x == c[0].x && c[i].y == c[0].y)continue;
if (c[i].t == 'R' || c[i].t == 'G')
{
if (cnt(c[i], c[0]) == 0)return false;
}
if (c[i].t == 'C')
{
if (cnt(c[i], c[0]) == 1)return false;
}
if (c[i].t == 'H')
{
for (int j = 0; j < 8; j++)
{
if (c[i].x + movh[j][0] == c[0].x && c[i].y + movh[j][1] == c[0].y
&& tab[c[i].x + mov[j / 2][0]][c[i].y + mov[j / 2][1]] == '0')
return false;
}
}
}
return true;
}
判断炮和车 是用cnt函数先判断是否在一条直线上然后比较这条直线上有多少棋子。
我觉得厉害是这个马的判断方式,也是我一直头疼的蹩马腿的方式
我们先来看mov和movh这两个数组
int mov[4][2] = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };
int movh[8][2] = { { -1,2 },{ 1,2 },{ 2,1 },{ 2,-1 },{ 1,-2 },{ -1,-2 },{ -2,-1 },{ -2,1 } };
每两个movh的坐标间就是mov的一个坐标,而必须这么定义的原因就是check函数判断是否蹩马腿的方式也就是j/2。
自问我是想不到的,这个真心有学习到。
3.cnt函数
int cnt(chess p1, chess p2)
{
int cnt = 0;
if (p1.x == p2.x)
{
int add = p1.y < p2.y ? 1 : -1;
for (int i = p1.y + add; i != p2.y; i += add)
{
if (tab[p1.x][i] != '0')cnt++;
}
}
else if (p1.y == p2.y)
{
int add = p1.x < p2.x ? 1 : -1;
for (int i = p1.x + add; i != p2.x; i += add)
{
if (tab[i][p1.y] != '0')cnt++;
}
}
else
cnt = -1;
return cnt;
}
首先判断的是两个棋子是否在同一条水平或垂直的线上。
再去数两个棋子间有多少的棋子
我觉得有趣的是add这个变量
其实比较p1.x和p2.x的大小然后保证小的在前也不失为一种其他的办法。
但这种方案总觉得 有点意思~