本人曾有两个思路恰与一位博主不谋而合,这里放上链接:
UVA1589 解题报告
思路1:对红方的每一个棋子,把他们的必杀区域(能吃掉对方的棋子的区域)都用代替,之后对黑方的帅,试着移动四个方位,如果四个方位都会碰到’’,那么红方将死对方。就是之前要检查一下红方是否会被黑方飞帅直线击杀。
思路2:与思路1相反,先移动黑方的帅,对每一个可能移动的方位,遍历所有红方的棋子,看红方棋子能否击杀黑方。如果对四个可能的移动方位,黑方都必死,那么红方将死黑方,否则,将不死。
思路1有个问题,那就是如果黑方吃掉红方一个棋子,可能会失效。
思路二有许多技巧:
1.将马的移动放入movh数组中,“将”的移动放入mov中,可以简化程序
2.炮、车、帅对对方的“将”限制原理类似,可以通过红方棋子和”将“之间的棋子数判断“将”是否被“check”,棋子数计算通过cntblk()实现
#include <iostream>
#include <iomanip>
#include<cassert>
#include <cstring>
using namespace std;
const int mov[4][2] = { 0,1,0,-1,1,0,-1,0 };
const int movh[8][2] = { -1,2,1,2,-1,-2,1,-2,2,1,2,-1,-2,1,-2,-1 };
int board[11][11], board0[11][11];
char type[8];
int cx[8], cy[8], N, hx, hy;
bool legal(int x, int y)
{
return x >= 1 && x <= 3 && y >= 4 && y <= 6;
}
int cntblk(int x1, int y1, int x2, int y2)
{
int cnt = 0;
if (y1 == y2)
{
int add = x1 < x2 ? 1 : -1;
for (int i = x1 + add; i != x2; i+=add) {
if (board[i][y1])
++cnt;
}
}
else if (x1 == x2)
{
int add = y1 < y2 ? 1 : -1;
for (int i = y1 + add; i != y2; i+=add) {
if (board[x1][i])
++cnt;
}
}
else cnt = -1;
return cnt;
}
bool check(int x,int y)
{
for (int i = 0; i < N; ++i)
{
if (x != cx[i] || y != cy[i])//判断“将”是否吃了红棋
{
if (type[i] == 'R' || type[i] == 'G')
{
if (cntblk(cx[i], cy[i], x, y)==0)
return true;
}
else if (type[i] == 'H')
{
for (int j = 0; j < 8; ++j)
{
if (cx[i] + movh[j][0] == x && cy[i] + movh[j][1] == y && !board[cx[i] + mov[j / 2][0]][cy[i] + mov[j / 2][1]])
return true;
}
}
else if (type[i] == 'C')
if (cntblk(cx[i], cy[i], x, y) == 1)return true;
}
}
return false;
}
int main()
{
while (cin >> N >> hx >> hy && N)
{
int win = 1;
memset(board0, 0, sizeof(board0));
for (int i = 0; i < N; ++i)
{
cin >> type[i] >> cx[i] >> cy[i];
board0[cx[i]][cy[i]] = type[i];
}
for (int i = 0; i < 4; ++i)
{
int hxcrnt = hx + mov[i][0], hycrnt = hy + mov[i][1];
if (legal(hxcrnt, hycrnt))
{
memcpy(board, board0, sizeof(board0));
board[hxcrnt][hycrnt] = 0;
if (!check(hxcrnt, hycrnt))win = 0;
}
}
if (win)cout << "YES" << endl;
else cout << "NO" << endl;
}
}