https://www.luogu.org/problem/show?pid=P3930
这道题,其实完全不需要你去你用什么高级算法,其实需要你的,是耐心地爆搜,像2015年斗地主一样了,但有一个坑,我没注意到,于是得了80分,那就是:因为进攻方是骑士,所以进攻方是不可能吃到骑士的。大体呢就是先把开始点和结束点记录下来,然后开结构体,结构体里面要有它当时棋盘的状态和进攻方所在位置,然后把那些敌方的记录下来,每次往8个方向枚举,符合条件(就是没跳出棋盘,不会被地方吃到) 。因为宽搜要快一些,所以我们用宽搜,要开一个队列,搜到了第一个吃到国王的就跳出来,返回步数。搜完后还不行,就返回1.
注意:如果跳到了敌方的一个棋子上,就要把那颗棋子去掉!#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int inf=0x3f3f3f3f;
struct wo{
char b[60][60];//棋盘状态
int x,y;//
};
queue<wo>p;
char a[60][60];
int vis[60][60];//记录有多少颗敌方棋子能吃到自己
int step[60][60];//记录到达当前点至少要用多少步
int n;
int dx[8]={1,1,-1,-1,2,2,-2,-2};//八个方向
int dy[8]={2,-2,2,-2,1,-1,1,-1};//八个方向
int startx,starty,endx,endy;//开始点和结束点
int judge(int x,int y){
if(x<=0||x>n)return 0;
if(y<=0||y>n)return 0;
if(vis[x][y])return 0;
return 1;
}
void queen(int x,int y){//皇后攻击范围内的
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i==x)||(j==y)||((i+j)==(x+y))||((i-j)==(x-y)))//横坐标一样,竖坐标一样,或者在同一条斜线上
vis[i][j]++;//能攻击到这一点
}
}
vis[x][y]--;//自己攻击不了自己!
}
void castle(int x,int y){//城堡攻击范围
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((i==x)||(j==y))//横坐标一样或竖坐标一样
vis[i][j]++;//能攻击到这一点
}
}
vis[x][y]--;//自己攻击不了自己!
}
void B(int x,int y){//主教攻击范围
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(((i+j)==(x+y))||((i-j)==(x-y)))//在同一条斜线上
vis[i][j]++;//就吃得到
}
}
vis[x][y]--;//自己攻击不了自己!
}
void knight(int x,int y){
for(int i=0;i<8;i++){
if(judge(x+dx[i],y+dy[i])){//在骑士的8个方向上,且在棋盘上
vis[x+dx[i]][y+dy[i]]++;//就吃得到
}
}
//因为攻击方也是骑士,所以攻击方吃不了
}
void solider(int x,int y){
vis[x+1][y-1]++;vis[x+1][y+1]++;//士兵只能攻击到两个点
}
void king(int x,int y){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(abs(x-i)<=1&&abs(y-j)<=1)vis[i][j]++;//国王的8个方向内能被吃到
}
}
vis[x][y]=0; //自己攻击不了自己!
}
void me(int x,int y){
startx=x,starty=y;//记录开始坐标
}
int solve(){
while(p.size())p.pop();
wo help;
wo save;
help.x=startx;
help.y=starty;
step[startx][starty]=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
help.b[i][j]=a[i][j];
}
}
for(int i1=1;i1<=n;i1++){
for(int j1=1;j1<=n;j1++){//一个一个地找敌方棋子,敌方棋子攻击范围内的就不能到
if(help.b[i1][j1]=='C')castle(i1,j1);
else if(help.b[i1][j1]=='K')knight(i1,j1);
else if(help.b[i1][j1]=='B')B(i1,j1);
else if(help.b[i1][j1]=='Q')queen(i1,j1);
else if(help.b[i1][j1]=='X')king(i1,j1);
else if(help.b[i1][j1]=='P')solider(i1,j1);
}
}vis[endx][endy]=0;//毕竟吃到国王就赢了,不需考虑其它
if(judge(help.x,help.y)==0)return -1;
p.push(help);
while(p.size()){
help=p.front();p.pop();
if(step[endx][endy]!=inf){
return step[endx][endy];
}
for(int i=0;i<8;i++){
memset(vis,0,sizeof(vis));
for(int i1=1;i1<=n;i1++){
for(int j1=1;j1<=n;j1++){//一个一个地找敌方棋子,敌方棋子攻击范围内的就不能到
if(help.b[i1][j1]=='C')castle(i1,j1);
else if(help.b[i1][j1]=='K')knight(i1,j1);
else if(help.b[i1][j1]=='B')B(i1,j1);
else if(help.b[i1][j1]=='Q')queen(i1,j1);
else if(help.b[i1][j1]=='X')king(i1,j1);
else if(help.b[i1][j1]=='P')solider(i1,j1);
}
}vis[endx][endy]=0;
if(judge(help.x+dx[i],help.y+dy[i])){//重点开始 ,如果跳到了棋盘上且不会被吃
if(step[help.x+dx[i]][help.y+dy[i]]>step[help.x][help.y]+1){//是走到当前点最优策略才行
step[help.x+dx[i]][help.y+dy[i]]=step[help.x][help.y]+1;
save.x=help.x+dx[i];save.y=help.y+dy[i];
for(int ii=1;ii<=n;ii++){
for(int jj=1;jj<=n;jj++){
save.b[ii][jj]=help.b[ii][jj];//继承状态
}
}
save.b[save.x][save.y]='.';//把被“我”吃到的变成点
p.push(save);
}//重点结束
}
}
}
return -1;
}
int main()
{
while(scanf("%d",&n)!=EOF){
memset(step,inf,sizeof(step));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]=='O')me(i,j);
if(a[i][j]=='X'){
endx=i,endy=j;//记录国王位置
}
}
}
printf("%d ",solve());
}
return 0;
}