原题见https://vjudge.net/problem/UVA-1589
大意是判断黑将军是否被红棋(红帅,红车,红马,红炮)将死。注意可以将帅吃,如果黑将和红帅正对面并且中间没有其他棋子,算黑棋胜利。
代码没有AC,但是udebug里面的1000多个数据全部通过。找不到问题,也不知道怎么回事,我就当格式出了错误吧。
(码了几天,估计20个小时了,还是不行。。。)
思路:
为了方便判断,定义一个10*9的数组用于存储棋子。
1、判断黑将是否能吃掉红帅:
如果黑将能直接吃掉红帅,那么黑棋就赢了,后面也不用判断了,所以一开始先判断这个。
判断起来也很简单,从黑将的位置开始纵向搜索就行了。
2、判断黑将是否有路可走(是否被将死)
黑将的移动范围有限,只能在如下的红色区域内移动
所以首先要先求出黑将能移动的点,然后判断这些点能不能移动。
当然,棋子A可能落在黑将能走的范围上。如果那个点没有被除了A以外的其他棋子攻击,
那我们就把这个棋子拿走,当做被黑帅吃了。
我们对黑将能走的所有点都进行,如果每个点都受到攻击,毋庸置疑黑将被将死了。
为了方便起见,下面把黑将能走的点称为“移动点”
(1)移动点来自马的攻击:
判断移动点是否受到马的攻击最为简单,即使要考虑到“别马脚”这种情况。
如下图所示,马最多能在8个点(红色)攻击移动点(蓝色),并且这8个点又被4个点(绿色)别住马脚了:
若移动点坐标为(0,0),那么这8个红色点的坐标分别为:
{-1,-2},{-2,-1},{1,-2},{2,-1},{-1,2},{-2,1},{1,2},{2,1}
对应地,有4个点能别住这些马,使其无法攻击到移动点。为{-1,-1},{1,-1},{-1,1},{1,1}
为了与上面8个红色的点一一对应,记为:
{-1,-1},{-1,-1},{1,-1},{1,-1},{-1,1},{-1,1},{1,1},{1,1}
上面这些坐标我叫做偏移量,
到时候通过移动点坐标+偏移量的方式就能将8个红点+4个绿点表示出来。
再判断一下是否超出棋盘范围,就能判断该点是否被马攻击了。
(2)来自车,帅的攻击
判断来自车,帅的攻击较为麻烦,因为要从移动点开始向四周探索。要写四个循环,循环内容还差不多,感觉十分繁琐,所以觉得较为麻烦。
实际上思路也是很简单的:向四周探索,看看第一个被发现的红棋是不是车或帅就行了。
(3)来自炮的攻击
最麻烦就是这个了,从移动点开始向四周探索,要判断第二个遇到的红棋是不是炮,所以比(2)还要复杂。
当然可以化简一下:
①如果第一个探索到的红棋是车或帅,就不必继续探索看看有没有炮了,反正这个点被车或帅攻击,迟早死翘翘
②如果第一个探索到的红棋是炮或马,就继续探索看看有没有炮
以上就是本题的大致思路了,下面是代码:
为了方便观察,附增上了棋盘显示功能,
B表示黑将,*表示安全的移动点
G表示红将,R表示红车,H表示红马,C表示红炮
如果黑将能直接吃掉红帅,什么安全的移动点都不显示出来,直接输出答案
代码如下:
/**
UVa 1589
**/
#include<stdio.h>
#include<iostream>
#include<windows.h>
using namespace std;
char bou[10][10];
//---------------------------------------------调试代码----------------------------------------------------------------
void color(int b){
HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
SetConsoleTextAttribute(hConsole, b) ;//颜色控制
}//颜色控制模块
//界面显示(测试用)
//B:黑方将军 *:黑方将军可移动范围
//G:红方将军 R:红方车 H:红方马 C:红方炮 #:红方攻击范围
void showBou(){
printf("\n\n");
for(int i=0;i<10;++i){
printf(" ");
for(int j=0;j<9;++j){
if(bou[i][j]!=NULL){
bou[i][j]=='B' || bou[i][j]=='*' ? color(11):color(12);
printf("%c",bou[i][j]);color(7);
}else{printf("+");}
if(j<8)printf("---");
}
if(i<9){
printf("\n ");
if(i!=4){
for(int k=0;k<9;++k){
if(((i==0 || i==7) && k==3) || ((i==1 || i==8) && k==4)){printf("| \\ ");}
else if(((i==0 || i==7) && k==4) || ((i==1 || i==8) && k==3)){printf("| / ");}
else printf("| ");
}
}else{printf(" -----汉界-----楚河-----");}
}
printf("\n");
}
}
//----------------------------------------------------------------------------------------------------------------------------*/
//--------------------------------核心代码------------------------------------------------------------------------------------
void clear(){
for(int i=0;i<10;++i){
for(int j=0;j<10;++j){
bou[i][j]=NULL;
}
}
}
//来自马的攻击
int HAT[8][2]={{-1,-2},{-2,-1},{1,-2},{2,-1},{-1,2},{-2,1},{1,2},{2,1}};//如果某个格子坐标为(0,0),可能被以下8个点的马攻击到(前提是马没有被别马脚)
int HHL[8][2]={{-1,-1},{-1,-1},{1,-1},{1,-1},{-1,1},{-1,1},{1,1},{1,1}};//以上8个点对应被别马脚的地方
bool horse(int y,int x){//黑将军某个可移动点的坐标
int m,n;//马的坐标
int m1,n1;//别马脚的地方
for(int i=0;i<8;++i){
m=x+HAT[i][0],n=y+HAT[i][1];
if(m>=0 && m<10 && n>=0 && n<9){
m1=HHL[i][0]+x,n1=HHL[i][1]+y;
if(bou[m][n]=='H' && (bou[m1][n1]==NULL || bou[m1][n1]=='*' || bou[m1][n1]=='#')){//该点有马而且没被别住
return true;
}
}
}
return false;
}
//来自将军和车的攻击
bool chariot(int x,int y){
bool t=false;
//横
for(int i=x-1;i>=0;--i){
if(bou[y][i]=='R') t=true;
if(bou[y][i]=='C' || bou[y][i]=='H') break;
}
for(int i2=x+1;i2<10;++i2){
if(bou[y][i2]=='R') t=true;
if(bou[y][i2]=='C' || bou[y][i2]=='H') break;
}
//纵
for(int j=y-1;j>=0;--j){
if(bou[j][x]=='R' || bou[j][x]=='G') t=true;
if(bou[j][x]=='C' || bou[j][x]=='H') break;
}
for(int j2=y+1;j2<10;++j2){
if(bou[j2][x]=='R' || bou[j2][x]=='G') t=true;
if(bou[j2][x]=='C' || bou[j2][x]=='H') break;
}
return t;
}
//来自炮的攻击
bool cannon(int x,int y){//黑将军某个可移动点的坐标
//寻找炮架。如果找到车或帅的话,我们不用管,反正也难逃一死了
int flag=false;//炮架
//横
for(int i=x-1;i>=0;--i){
if(bou[y][i]=='C' && flag) return true;
if(bou[y][i]!=NULL && bou[y][i]!='C' && flag) return false;
if(bou[y][i]=='C' || bou[y][i]=='H') {
flag=true;
}
}flag=false;
for(int i2=x+1;i2<10;++i2){
if(bou[y][i2]=='C' && flag) return true;
if(bou[y][i2]!=NULL && bou[y][i2]!='C' && flag) return false;
if(bou[y][i2]=='C' || bou[y][i2]=='H') {
flag=true;
}
}flag=false;
//纵
for(int j=y-1;j>=0;--j){
if(bou[j][x]=='C' && flag) return true;
if(bou[j][x]!=NULL && bou[j][x]!='C' && flag) return false;
if(bou[j][x]=='C' || bou[j][x]=='H') {
flag=true;
}
}flag=false;
for(int j2=y+1;j2<10;++j2){
if(bou[j2][x]=='C' && flag) return true;
if(bou[j2][x]!=NULL && bou[j2][x]!='C' && flag) return false;
if(bou[j2][x]=='C' || bou[j2][x]=='H') {
flag=true;
}
}
return false;
}
//判断是否被将死
int judge(int m,int n){
//看看黑将是否能吃掉红帅
for(int z=m;z<10;++z){
if(bou[z][n]=='C' || bou[z][n]=='H' || bou[z][n]=='R') break;
if(bou[z][n]=='G') return 1;
}
//确定黑方可移动范围
int canMove=0;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int x,y;
//把黑将能吃的棋子都消灭掉
for(int i1=0;i1<4;++i1){
x=n+dir[i1][0],y=m+dir[i1][1];
if(x>2 && x<6 && y>=0 && y<3){
// bou[y][x]='#';
}
}
for(int i=0;i<4;++i){
x=n+dir[i][0],y=m+dir[i][1];
if(x>2 && x<6 && y>=0 && y<3){
if(horse(x,y) || chariot(x,y) || cannon(x,y)){
// bou[y][x]='#';
}else{
bou[y][x]='*';
canMove++;
}
}
}
return canMove;
}
int out[10000];
int main(){
int t,m,n,c;
int f=0;
while(scanf("%d",&t)>0){
if(t>0){
clear();
int w,q;
scanf("%d %d",&w,&q);
bou[w-1][q-1]='B';
while(--t>=0){
getchar();
c=getchar();
scanf("%d%d",&m,&n);
bou[m-1][n-1]=c;
}
judge(w-1,q-1)==0 ? printf("YES\n") : printf("NO\n");
// judge(w-1,q-1)==0 ? out[f]=1:out[f]=0;//一次性输出所有答案时用
++f;
showBou();//显示棋盘
}else{
break;
}
}
// printf("\n");
/*一次性输出所有答案
for(int i=0;i<f;++i){
printf("%s\n",out[i]==1 ? "YES" : "NO");
}
printf("\n");
*/
return 0;
}