《算法竞赛入门经典》UVA1589

《算法竞赛入门经典》UVA1589

 

题目

 

 
 

题解

大框架

首先构建函数的大框架——这个问题要怎么解决呢?
可选项:

  1. 分析帝宫九个位置可否放置将或帅,储存在二位数组Room里(0为不可放置,1为可放置)。判断将或帅一步内可移动的位置在Room中的值是否为1。
  2. 将所有棋子置于容器中,判断每一个将或帅可移动的位置循环一次容器,确认是否被将军。

可行性分析:

  1. 可行,帝宫九个位置,需要一个3*3的数组即可,只用循环一次棋子和一次将帅的移动方式,时间上的复杂程度也不高。
  2. 可行,按规定是只有7个对方棋子,假设将帅位置在中间(最多的移动方式-4次),所需的计算量为28个函数运算,时间上复杂程度也没有超出。

 

例外情况

  1. 考虑对方飞将的可能性(中国象棋里其实不存在这种情况,博主分析时忽略了,在做Udebug才知道还有这种坑爹操作)
  2. 注意,你的棋子是可能被吃掉的,也就是说当炮、马、将军三者连在一起时,将军可以吃掉马摆脱被将死的局面。或者车在将的左右且同处于帝宫内,可能不构成将军。

 

构建函数

充分考虑各种情况后可以开始写各个棋子的函数了。再次之前,我们先定义一下头文件和全局变量。

#include <cstdio>
#include <cstring>
#include <math.h>
using namespace std;
#define f(i,m,n) for (int i = m; i<n; i++)


int B[11][10]= {0};
int M[5][2]= {0};
int RM[3][3];
int BGX=1,BGY=1,FC = 1;

struct Chess {
    char ty;
    int x,y;
};
  • cstdio -> input ; cstring -> memset ; math.h -> cos/sin
  • 一定要cstring,网上那个c++编译器不吃string这个头文件
  • 经常调用的循环也定义一下,可以简洁很多
  • B是Board的缩写,定义棋盘,方便车炮帅等函数的构造
  • M是Move的缩写,定义黑方将军可移动位置,主要是防止红方棋子被吃和验证帝宫内位置是否可达到
  • RM是Room的缩写,确定帝宫里哪些位置是可以达到的。
  • FC是Face Check的缩写,防止飞将的异常情况
  • 定义一个struct,main函数中可以生成一个struct的array,储存棋子。

 

函数“马”

可以先写“马”的函数,因为马即使被吃了,也不会有大的影响(马走日,若将能吃掉马,这一马必定攻击不到将)

void Horse (int x,int y){
    int x1, y1;
    f(m,1,5){f(n,0,2){
        if(B[x1 = x+sin(m*M_PI/2)][y1 = y+cos(m*M_PI/2)] == 0){
            x1= x + sqrt(5)*sin((22.5+(2*m-n)*45)*M_PI/180) + 0.5;
            y1= y + sqrt(5)*cos((22.5+(2*m-n)*45)*M_PI/180) + 0.5;
            if (3<x1 && x1<7 && 0<y1 && y1<4) RM[x1-4][y1-1] = 0;
        }
    }}
}
  • 输入为马的 x,y 值
  • if 那一行确认没有蹩马脚的情况
  • 这里调用了数学函数,马行走的路线是1:2:√5, 每个角间隔为45°。
  • sin 和 cos 都是弧度制,不知道为什么 /180一定要放在最后。
  • 另外记得加0.5,所有的float -> int 都是使用了floor()函数。

 
 

#include <cstdio>
#include <string>
#include <math.h>
using namespace std;
#define f(i,m,n) for (int i = m; i<n; i++)


int B[11][10]= {0};
int M[5][2]= {0};
int RM[3][3];
int BGX=1,BGY=1,FC = 1;

struct Chess {
    char ty;
    int x,y;
};

int verify (int x,int y){
    f(n,0,4){
        if (M[n][0]==x&&M[n][1]==y){return 1;}
    }
    return 0;
}

void Ch (int x,int y,int L,int R,char ty){
    int n = R==0?x:y, sum=0,bk=100;
    if (n>L){
        int c = L; L = n; n = c;
    }
    f(i,n+1,L){
        if(R==0?B[i][y]:B[x][i]){
            if(bk == 100)bk = i;
            sum ++;
        }
    }
    if (ty == 'C'?sum==1:sum==0){
        if(ty != 'G'||x!=BGX){
        f(i,0,3){ 
            if (R==0){
                if ((ty=='C'&&i==bk-4&&verify(bk,y))||(i==x-4&&verify(x,y))) continue;}
            else{
                if ((ty=='C'&&i==bk-1&&verify(x,bk))||(i==y-1&&verify(x,y))) continue;}
            R==0?RM[i][y-1]=0:RM[x-4][i] = 0;
        }}
        else FC =0;
    }
}

void Horse (int x,int y){
    int x1, y1;
    f(m,1,5){f(n,0,2){
        if(B[x1 = x+sin(m*M_PI/2)][y1 = y+cos(m*M_PI/2)] == 0){
            x1= x + sqrt(5)*sin((22.5+(2*m-n)*45)*M_PI/180) + 0.5;
            y1= y + sqrt(5)*cos((22.5+(2*m-n)*45)*M_PI/180) + 0.5;
            if (3<x1 && x1<7 && 0<y1 && y1<4) RM[x1-4][y1-1] = 0;
        }
    }}
}

void C (char ty, int x, int y){
    int sum = 0;
    if (y<4)Ch(x,y,BGX,0,ty);
    if (3<x && x<7)Ch(x,y,BGY,1,ty);
}

int main (){
    memset(RM,1,sizeof(RM));
    int N,x,y;
    Chess O[9];
    while (scanf("%d%d%d\n",&N,&BGY,&BGX)==3&&N){
        f(n,0,4){
            x= BGX+sin(n*M_PI/2)+0.5;
            y= BGY+cos(n*M_PI/2)+0.5;
            if(3<x&&x<7&&0<y&&y<4){
                M[n][0]=x;
                M[n][1]=y;
            }
        }
        f(i,0,N){
            scanf("%c%d%d\n",&O[i].ty,&O[i].y,&O[i].x);
            B[O[i].x][O[i].y] = 1;
        }
        f(i,0,N){
            O[i].ty == 'H'?Horse(O[i].x,O[i].y):C(O[i].ty,O[i].x,O[i].y);
        }
        f(n,0,4){
            if(M[n][0]){
                if (!FC||RM[M[n][0]-4][M[n][1]-1]) {
                printf("NO\n");
                break;}
            }
            if (n==3) printf("YES\n");
        }
        memset(B,0,sizeof(B));
        memset(M,0,sizeof(M));
        memset(RM,1,sizeof(RM));
        FC = 1;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值