Uva 1589 xiangqi

模拟是否将死的局面。
马 : 向各个方向先走两步,再往垂直与这个方向上走一步,若这个方向的第一个位置有棋子,则这个方向上不能走。

炮: 直线方向上的第一个棋子和第二个棋子之间的位置都可以吃。

车: 上下左右

将/帅: 不能见面,若是见面,使它们见面的那一方输,所以开始时要特判一下,如果此时将帅见面了,则是黑方输,输出NO

这里特别注意的是,将是可以吃棋子的,也即是可以有将先吃了一颗红方的棋,然后另外的棋子可以走到这里。也就是说标记时要考虑到有棋子的位置能否走。

上面考虑清楚了,基本代码就出来了。
毕竟将能走的位置也是有限的,顶多4个,考虑这几个位置上是不是都有红方的棋子能走到。
这道题wa了很多次…..本来是前天写的题,今天趁头脑还比较清醒的时候拿出来写一写,果然理一理思路一发过了…..

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
#define maxn 15
int n,ja,jb;
int ori[maxn][maxn];
int vis[maxn][maxn];
int bcan[4][10];
int way[4][2] = {-1,0,1,0,0,-1,0,1};

struct qz
{
    int k;
    int i,j;
    qz(int a,int b,int c)
    {
        k = a; i = b; j = c;
    }
    qz(){}
}q[maxn];
int ra,rb;

int check(int i,int j)
{
    if(i > 10 || i < 1 || j > 9 || j < 1) return 0;
    else return 1;
}
int lf(int w,int i,int j,int k)         //四个方向上找到一个棋子,k是看标不标记找的路上的
{
    int ci = i,cj = j;
    while(1)
    {
        ci = ci+way[w][0] , cj = cj + way[w][1];

        if(check(ci,cj) == 0) return -1;  //找到边界了
        if(k == 1) vis[ci][cj] = 1;
        if(ori[ci][cj] == 1)
        {
            if(w <= 1) return ci;
            else return cj;
        }
    }

}
int msize = 0;
int solve()
{
    //cout<<"n "<<n<<endl;
    for(int i = 0; i < n ;i ++)
    {
        if(q[i].k == 1)
            continue;
        else if(q[i].k == 2)        //horse  考虑憋马腿的情况。
        {
            for(int j = 0; j < 4 ; j++)
            {
                int ci = q[i].i+way[j][0],cj = q[i].j + way[j][1];
                if(check(ci,cj))
                    if(ori[ci][cj] == 1) continue;

                int i1,j1,i2,j2;
                int mi = q[i].i+way[j][0]*2, mj = q[i].j + way[j][1]*2;
                if(j <= 1)
                {
                    i2 = i1 = mi; j1 = mj + 1; j2 = mj-1;
                }
                else
                {
                    j2 = j1 = mj; i1 = mi+1; i2 = mi-1;
                }
                if(check(i1,j1))    vis[i1][j1] = 1;
                if(check(i2,j2))    vis[i2][j2] = 1;
            }
        }
        else if(q[i].k == 3)
        {
            for(int j = 0; j < 4; j++)
            {
                int one = lf(j,q[i].i,q[i].j,0);
                if(one != -1)       //找到炮台
                {
                    if(j <= 1)
                        lf(j,one,q[i].j,1);     //标记第一个后面的所有位置
                    else
                        lf(j,q[i].i,one,1);
                }
            }
        }
        else
        {
             for(int j = 0; j < 4 ; j++)
                lf(j,q[i].i,q[i].j,1);
        }
    }
    for(int i = 0; i < msize; i++)
    {
        if(vis[bcan[i][0]][bcan[i][1]] == 0)
            return 0;
    }
    return 1;
}

int main()
{
    char s[2];
    while(~scanf("%d%d%d",&n,&ja,&jb) &&n+ja+jb)
    {
        int a,b;
        msize = 0;
        memset(vis,0,sizeof(vis));
        memset(ori,0,sizeof(ori));
        memset(bcan,0,sizeof(bcan));

        for(int i = 0; i < n ; i++)
        {
            cin>>s>>a>>b;
            int kind = -1;
            if(s[0] == 'G')
                ra = a,rb = b, kind = 1;
            else if(s[0] == 'H') kind = 2;
            else if(s[0] == 'C') kind = 3;
            else kind = 4;
            ori[a][b] = 1;
            q[i] = qz(kind,a,b);
        }

        for(int i = 0; i < 4 ; i++)    //红方的帅能否直接吃掉将,将这个位置标记
        {
            int bi = ja+way[i][0],bj = jb+way[i][1];
            if(bi <= 3 && bi >= 1 && bj >= 4 && bj <= 6)
                bcan[msize][0] = bi,bcan[msize++][1] = bj;
            if(rb == bj)
            {
                int flag = 0;
                for(int j = ra-1; j > bi; j--)
                    if(ori[j][bj] == 1)
                    {  flag = 1;}
                if(flag == 0)
                    vis[bi][bj] = 1;
            }
        }

        if(rb == jb)    //初始 将能否直接吃掉帅
        {
            int flag = 0;
            for(int i = ra-1; i > ja; i--)
                if(ori[i][jb] == 1) flag = 1;
            if(flag == 0) {printf("NO\n");continue;}
        }

        if(solve())
            printf("YES\n");
        else printf("NO\n");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值