/*好恶心的一道题,说明自己细节考虑得还不够。最恨的就是这种不难的题还做不对。
经过7个小时的苦苦检查后,终于找到了错误的地方,棋盘恢复上一状态的时候竟然只恢复了一个点,
太傻了!!!改过之后终于AC了。
1.需要考虑红子被黑将吃掉的情况。
2.考虑飞将军的情况。
把能杀掉的点都标记为-1,有棋子的点为1,其余点为0.
穷举黑将走的4个方向,若4个方向的标记都为-1(能被杀掉),则被将死,否则将不死。
具体细节见代码,代码写得有点冗长,用CIN读取输入会方便很多。*/
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int bx,by,pos; //bx,by代表黑将的初始位置,pos为被黑将吃掉的棋子的位置
int G[2],R[10][2],H[10][2],C[10][2];//G为红帅,R代表车,H代表马,C代表炮
int rtop,htop,ctop; //分别记录车个数、马个数、炮个数
const int dx[4]={-1,1,0,0};//棋子移动方向
const int dy[4]={0,0,-1,1};//上、下、左、右
const int nextx[8]={1,-1,-2,-2,-1,1,2,2};//马移动方向
const int nexty[8]={-2,-2,-1,1,2,2,1,-1};//顺时针
int grid[11][11]; //棋盘
void FillUp(int x,int y)//向上能杀的地方
{
int i;
for(i=x;i>=1&&(grid[i][y]!=1);i--)grid[i][y]=-1;
}
void FillDown(int x,int y)//向下能杀的地方
{
int i;
for(i=x;i<=10&&(grid[i][y]!=1);i++)grid[i][y]=-1;
}
void FillLeft(int x,int y)//向左能杀的地方
{
int i;
for(i=y;i>=1&&(grid[x][i]!=1);i--)grid[x][i]=-1;
}
void FillRight(int x,int y)//向右能杀的地方
{
int i;
for(i=y;i<=9&&(grid[x][i]!=1);i++)grid[x][i]=-1;
}
void CheckFlyGeneral()//飞将军能杀的地方
{
int i,flyGeneral=1;
for(i=G[0]-1;i>=1;i--)
{
if(grid[i][G[1]]==1)flyGeneral=0;//路上有棋子挡着,不能杀
}
if(flyGeneral)
{
for(i=1;i<=3;i++)grid[i][G[1]]=-1;
}
}
void CheckChariot()//车能杀掉的地方
{
int rx,ry,nrx,nry,i,j;
for(i=0;i<rtop;i++)
{
rx=R[i][0];ry=R[i][1];
if(rx<=0||ry<=0)continue;//表示该棋子被吃了
for(j=0;j<4;j++)
{
nrx=rx+dx[j];nry=ry+dy[j];
if(nrx>=1&&nrx<=10&&nry>=1&&nry<=9)
{
if(j==0)FillUp(nrx,nry);
if(j==1)FillDown(nrx,nry);
if(j==2)FillLeft(nrx,nry);
if(j==3)FillRight(nrx,nry);
}
}
}
}
void CheckHorse()//马能杀掉的地方
{
int i,j,k;
int hx,hy,nhx,nhy;
int hobble[4],hbox,hboy;
memset(hobble,0,sizeof(hobble));
for(i=0;i<htop;i++)
{
hx=H[i][0];hy=H[i][1];
if(hx<=0||hy<=0)continue;//表示该棋子被吃了
for(j=0;j<4;j++) //标记蹩脚的方向
{
hbox=hx+dx[j];hboy=hy+dy[j];
if(grid[hbox][hboy]==1)hobble[j]=1;
}
for(j=0;j<8;j++)
{
if(hobble[0]&&(j==2||j==3))continue;
if(hobble[1]&&(j==6||j==7))continue;
if(hobble[2]&&(j==0||j==1))continue;
if(hobble[3]&&(j==4||j==5))continue;
nhx=hx+nextx[j];nhy=hy+nexty[j];
if(nhx>=1&&nhx<=10&&nhy>=1&&nhy<=9)
{
if(grid[nhx][nhy]!=1)grid[nhx][nhy]=-1;
}
}
}
}
void CheckCannon()//炮能杀掉的地方
{
int i,j,k;
int cx,cy,ncx,ncy,vx,vy;
for(i=0;i<ctop;i++)
{
cx=C[i][0];cy=C[i][1];
if(cx<=0||cy<=0)continue;//表示该棋子被吃了
for(j=0;j<4;j++)
{
ncx=cx+dx[j];ncy=cy+dy[j];
if(ncx>=1&&ncx<=10&&ncy>=1&&ncy<=9)//隔山打牛,先找一个子,再杀他后面的
{
if(j==0)
{
for(k=ncx;k>=1;k--)
{
if(grid[k][ncy]==1)break;
}
if(k>0)
{
vx=k-1;vy=ncy;
FillUp(vx,vy);
}
}
if(j==1)
{
for(k=ncx;k<=10;k++)
{
if(grid[k][ncy]==1)break;
}
if(k<=10)
{
vx=k+1;vy=ncy;
FillDown(vx,vy);
}
}
if(j==2)
{
for(k=ncy;k>=1;k--)
{
if(grid[ncx][k]==1)break;
}
if(k>0)
{
vx=ncx;vy=k-1;
FillLeft(vx,vy);
}
}
if(j==3)
{
for(k=ncy;k<=9;k++)
{
if(grid[ncx][k]==1)break;
}
if(k<=9)
{
vx=ncx;vy=k+1;
FillRight(vx,vy);
}
}
}
}
}
}
void Check()//将
{
CheckFlyGeneral();
if(rtop)CheckChariot();
if(htop)CheckHorse();
if(ctop)CheckCannon();
}
int FindNode(int x,int y)//找到被吃的棋子
{
int i;
pos=-1;
for(i=0;i<ctop;i++)
{
if(C[i][0]==x&&C[i][1]==y)
{
C[i][0]=-10;C[i][1]=-10;
pos=i;
return 1;
}
}
for(i=0;i<htop;i++)
{
if(H[i][0]==x&&H[i][1]==y)
{
H[i][0]=-10;H[i][1]=-10;
pos=i;
return 2;
}
}
for(i=0;i<rtop;i++)
{
if(R[i][0]==x&&R[i][1]==y)
{
R[i][0]=-10;R[i][1]=-10;
pos=i;
return 3;
}
}
return 0;
}
void Recovery(int x,int y,int state)//恢复棋盘初始状态
{
switch(state)
{
case 1:
C[pos][0]=x;C[pos][1]=y;
break;
case 2:
H[pos][0]=x;H[pos][1]=y;
break;
case 3:
R[pos][0]=x;R[pos][1]=y;
break;
}
}
int CheckMate()//检查能否被将死
{
int i;
int nbx,nby,status;
Check();
int origin[11][11];
memcpy(origin,grid,sizeof(grid));//记录棋盘初始状态
for(i=0;i<4;i++)
{
nbx=bx+dx[i];nby=by+dy[i];
if(nbx>=1&&nbx<=3&&nby>=4&&nby<=6)
{
switch(grid[nbx][nby])
{
case -1:
break;
case 0:
return 0;//这个地方不能被杀到
break;
case 1:
status=FindNode(nbx,nby);
grid[nbx][nby]=0;
Check();
if(grid[nbx][nby]==0)return 0;//吃掉棋子后,这个地方不能被杀到
Recovery(nbx,nby,status);//恢复初始状态
memcpy(grid,origin,sizeof(origin));//恢复棋盘初始状态
break;
}
}
}
return 1;
}
int main()
{
int N,i,x,y;
char mode;
while(cin>>N>>bx>>by)
{
if(!(N+bx+by))break;
memset(grid,0,sizeof(grid));
grid[bx][by]=-1;//一来就被将了,标记被-1,表示能被杀掉
rtop=htop=ctop=0;
for(i=0;i<N;i++)
{
cin>>mode>>x>>y;
grid[x][y]=1;//有棋子的地方标记为1
switch(mode)
{
case'G':
G[0]=x;G[1]=y;
break;
case'R':
R[rtop][0]=x;R[rtop++][1]=y;
break;
case'H':
H[htop][0]=x;H[htop++][1]=y;
break;
case'C':
C[ctop][0]=x;C[ctop++][1]=y;
break;
}
}
if(CheckMate())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
2011福州赛区区域赛 - A - Xiangqi - HDU - 4121
最新推荐文章于 2022-02-25 21:57:21 发布