HDU 4121 Xaingqi

这道题是2011年福州赛区的签到提,但是我却做了三天,愧疚。。。

不过这道题有个狗逼之处,就是他的炮兵走法是错误的。。。(这道题只要炮兵和目标之间有个炮架就可以吃了,但是正确规则是有炮架时炮只能吃炮架后面第一个棋子。)


不过也学到了模拟题的套路,就是首先想思路,写伪代码(流程图?),然后(重要!)把题目给的数据模拟一遍,没问题就写出来,最后再把题目给的数据模拟一边!


具体到这道题,就是首先bg(black general)先动,考虑能不能直接general fly结束游戏,不能就考虑4个方向(注意回溯和in palace条件),之后再考虑红方旗子能否吃掉这个位置的black general。


代码:

#include<bits/stdc++.h>
using namespace std;
int n,bg_x,bg_y,rg_x,rg_y,a[12][12];to record the information of the whole picture
bool ans;//b represents whether there is a place;c represents whether it is safe
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-2,2,2,-1,1,-1,1};
const int ddy[]={-1,1,-1,1,-2,-2,2,2};
/*in 2-d array a,that is the explanation:
0:empty
1:black general
2:red general(G)
3:red chariot(R)
4:red horse(H)
5:red cannon(C)
*/
int center,up,down,leftt,rightt;
bool isinboard(int x,int y)
{
    if((x>=1)&&(x<=10)&&(y>=1)&&(y<=9))
        return true;
    else
        return false;
}
bool isinpalace(int x,int y)//whether the black general is in palace
{
    if((x>=1)&&(x<=3)&&(y>=4)&&(y<=6))
        return true;
    else
        return false;
}
void read(void)
{
    int xx,yy;
    string input;
    char temp;
    for(int i=0;i<n;i++)
    {
        cin>>input>>xx>>yy;
        temp=input[0];
        switch(temp)
        {
            case 'G':
            {
                a[xx][yy]=2;
                rg_x=xx;
                rg_y=yy;
                break;
            }
            case 'R':
            {
                a[xx][yy]=3;
                break;
            }
            case 'H':
            {
                a[xx][yy]=4;
                break;
            }
            case 'C':
            {
                a[xx][yy]=5;
                break;
            }
        }
    }
}
bool fly(int aa,int bb,int cc,int dd)
//whether a general at (a,b) could general fly another general at (c,d)
{
    if(bb!=dd)
        return false;
    bool flag=true;//suppose it could general fly
    for(int i=min(aa,cc)+1;i<max(aa,cc);i++)
        if(a[i][bb])
            flag=false;
    return flag;
}
bool isclear(int aa,int bb,int cc,int dd)
//The road in between(a,b) and (c,d)(except for these 2 points is clear)
//if they are not in a line return false
{
    if((aa!=cc)&&(bb!=dd))
        return false;
    if(aa==cc)
    {
        bool flag=true;
        for(int j=min(bb,dd)+1;j<max(bb,dd);j++)
            if(a[aa][j])
                flag=false;
        return flag;
    }
    if(bb==dd)
    {
        bool flag=true;
        for(int i=min(aa,cc)+1;i<max(aa,cc);i++)
            if(a[i][bb])
                flag=false;
        return flag;
    }
}
bool issafe(void)
{
    int xxx,yyy,xxxx,yyyy;
    for(int i=1;i<=10;i++)
        for(int j=1;j<=9;j++)
        {
            if((a[i][j]==2)&&fly(rg_x,rg_y,bg_x,bg_y))
                return false;
            if((a[i][j]==3)&&isclear(bg_x,bg_y,i,j))
                return false;
            if(a[i][j]==4)
            {
                for(int k=0;k<8;k++)
                {
                    xxx=i+ddx[k];
                    yyy=j+ddy[k];
                    if((xxx==bg_x)&&(yyy==bg_y))
                    {
                        xxxx=i+dx[k/2];
                        yyyy=j+dy[k/2];//the middle point
                        if(!a[xxxx][yyyy])//Actually we do not need to check whether the (xxxx,yyyy)is legal here
                            return false;
                    }
                }
            }
            if(a[i][j]==5)
            {
                if(i==bg_x)
                {
                    int cnt=0;
                    for(int jj=min(j,bg_y)+1;jj<max(j,bg_y);jj++)
                    {
                        if(a[i][jj])
                            cnt++;
                    }
                    if(cnt==1)
                        return false;
                }
                if(j==bg_y)
                {
                    int cnt=0;
                    for(int ii=min(i,bg_x)+1;ii<max(i,bg_x);ii++)
                        if(a[ii][j])
                            cnt++;
                    if(cnt==1)
                        return false;
                }
            }



        }
        return true;
}
void backup(int xx,int yy)
{
    center=a[xx][yy];
    up=a[xx-1][yy];
    down=a[xx+1][yy];
    leftt=a[xx][yy-1];
    rightt=a[xx][yy+1];
}
void recover(int xx,int yy)
{
    a[xx][yy]=center;
    a[xx-1][yy]=up;
    a[xx+1][yy]=down;
    a[xx][yy-1]=leftt;
    a[xx][yy+1]=rightt;
}
int main(void)
{
    int xx,yy;
    //freopen("in","r",stdin);
    //freopen("out","w",stdout);
    while(cin>>n>>bg_x>>bg_y)
    {
        ans=true;//suppose checkmate will happen
        if(n+bg_x+bg_y==0)
            break;
        memset(a,0,sizeof(a));
        a[bg_x][bg_y]=1;
        //read in the other information
        read();
        //to check whether black general could generally fly in the next step
        if(fly(bg_x,bg_y,rg_x,rg_y))
            ans=false;
        else
        {
            xx=bg_x;
            yy=bg_y;//record the position of bg(now)
            backup(xx,yy);
            for(int k=0;k<4;k++)
            {
                recover(xx,yy);
                a[xx][yy]=0;
                bg_x=xx+dx[k];
                bg_y=yy+dy[k];
                if(!isinpalace(bg_x,bg_y))
                    continue;
                a[bg_x][bg_y]=1;

                if(issafe())
                {
                    //printf("Now the position is(%d,%d)\n",bg_x,bg_y);
                    //printf("a[1][4]=%d  a[1][5]=%d\n",a[1][4],a[1][5]);
                    ans=false;
                }
            }
        }
        if(ans)
            printf("YES\n");
        else
            printf("NO\n");

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值