UVA1589 解题报告

UVA1589

曾经想过两种不同的思路:

思路1:对红方的每一个棋子,把他们的必杀区域(能吃掉对方的棋子的区域)都用*代替,之后对黑方的帅,试着移动四个方位,如果四个方位都会碰到'*',那么红方将死对方。就是之前要检查一下红方是否会被黑方飞帅直线击杀。

思路2:与思路1相反,先移动黑方的帅,对每一个可能移动的方位,遍历所有红方的棋子,看红方棋子能否击杀黑方。如果对四个可能的移动方位,黑方都必死,那么红方将死黑方,否则,将不死。

思路1有个问题,那就是如果黑方吃掉红方一个棋子,可能会失效。

我第一次用思路1做,测了很多测试数据,发现思路1的问题的解决实际上就是要用思路2.

代码如下图:

其中Red是红方棋子的数组,print函数是为了能可视化打印出棋盘。

采用思路2,之后,发现几个陷阱:

1.continue之前记得还原棋盘

2.continue和break有时容易混淆

3.把判断边界单独弄成一个函数

4.对不同的单位,可以用dx【n】,dy【n】抽象表示,接下来便是能用一个循环表示,简化代码

5.先编写主程序框架,遇到难写的先用一个函数代替。先保证主要精力再框架的正确性,编写函数时也是采用这样的思路

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cctype>
#include <iostream>
int field[12][12];
int N,b_x,b_y;
using namespace std;
class Chess{
    public:
    char ch;
    int x;
    int y;
};
bool isInPalace(int x,int y)
{
    return 1<=x && x<=3 && 4<=y && y<=6;
}
bool isInBorder(int x,int y)
{
    if(1<=x && x<=10 && 1<=y && y<=9)
        return true;
    else
        return false;
}
bool catched_by(const Chess& chess,int bx,int by)
{
    //nx,ny 是对方棋子的postion
    /*  如果自己已经被吃掉,那就肯定不能吃掉对方    */
    if(chess.x==bx && chess.y==by)
    {
        return false;
    }
    //判断chess的种类

    //如果是车或者帅
    if(chess.ch=='R'|| chess.ch=='G')
    {
        //方位控制
        int dx[4]={1,0,-1,0};
        int dy[4]={0,1,0,-1};
        for(int i=0;i<4;i++)
        {
            int nx=chess.x;
            int ny=chess.y;
            //对该方位不断直线搜索
            while(true)
            {
                nx+=dx[i];
                ny+=dy[i];
                // 如果越界或者遇到红方棋子
                if(!isInBorder(nx,ny)||isupper(field[nx][ny]) )
                    break;
                else if(field[nx][ny]=='b')//吃掉对方
                return true;
            }
        }
    }
    else if(chess.ch=='H')
    {
        //马的8种可能方位
        int dx[8]={2,1,-2,-1, 2,1,-2,-1};
        int dy[8]={1,2, 1, 2,-1,-2,-1,-2};
        //对每一种方位
        for(int i=0;i<8;i++)
        {
           int nx=chess.x;
           int ny=chess.y;
           //如果没有磐马角
           if(isInBorder(nx+(dx[i]/2),ny+(dy[i]/2))  && field[nx+(dx[i]/2)][ny+(dy[i]/2)]==0)
           {
               nx+=dx[i];ny+=dy[i];
               //如果吃掉黑方的帅
               if(isInBorder(nx,ny)&& field[nx][ny]=='b')
               return true;

           }

        }
    }
    else if(chess.ch=='C')
    {
        //炮的四种打击方向
        int dx[4]={1,-1,0,0};
        int dy[4]={0,0,1,-1};
        //针对每一个方向
        for(int i=0;i<4;i++)
        {
            int nx=chess.x;
            int ny=chess.y;
            //找到第一个炮台
            enum found{isOut=1,isBlack,isFriend};
            found paoTai=isOut;
            while(true)
            {
                nx+=dx[i];
                ny+=dy[i];
                //如果找到炮台,就跳出循环

                if(!isInBorder(nx,ny))
                {
                    paoTai=isOut;
                    break;
                }
                else
                {
                    if(field[nx][ny]=='b')
                    {
                        paoTai=isBlack;
                        break;
                    }
                    else if(isupper(field[nx][ny]))
                    {
                        paoTai=isFriend;
                        break;
                    }
                }
            }
            //如果paotai== isFriend 表示找到炮台
            if(paoTai!=isFriend)
                continue;
            //找黑方
            while(true)
            {
                nx+=dx[i];
                ny+=dy[i];
                if(!isInBorder(nx,ny))
                {
                    break;
                }
                else
                {
                    if(field[nx][ny]=='b')
                    {
                        return true;
                    }
                    else if(isupper(field[nx][ny]))
                    {
                        break;
                    }
                }
            }

        }

    }

    return false;
}
bool catched_by(const vector<Chess>& Red,int nx,int ny)
{
    for(int i=0;i<N;i++)
    {
        if(catched_by(Red[i],nx,ny))
        {
            return true;
        }
    }
    return false;
}

void print()
{
    for(int i=1;i<=10;i++)
    {
        for(int j=1;j<=9;j++)
        {
            if(field[i][j]!=0)
            {
                printf("%c",field[i][j]);
            }

            else
                printf("O");
        }
        cout<<endl;
    }
    cout<<endl;
}

bool black_win()
{
    int dx[4]={1,0,-1,0};
    int dy[4]={0,1,0,-1};
        for(int i=0;i<4;i++)
        {
            int nx=b_x;
            int ny=b_y;
            //对该方位不断直线搜索
            while(true)
            {
                nx+=dx[i];
                ny+=dy[i];
                // 如果越界或者遇到红方棋子
                if(isInBorder(nx,ny))
                {
                    if(field[nx][ny]=='G')
                        return true;
                    else if(field[nx][ny]!=0)
                        return false;
                }
                else break;//如果遇到出界就赶紧推出这个直线搜索循环

            }
        }
        return false;
}

int main()
{
    //b represent 黑方的帅
    while(cin>>N>>b_x>>b_y&&N)
    {
        //初始化field数组
        memset(field,0,sizeof(field));
        vector<Chess> Red(N);
        for(int i=0;i<N;i++)
        {
            cin>>Red[i].ch>>Red[i].x>>Red[i].y;
            field[Red[i].x][Red[i].y]=Red[i].ch;
        }
        //draw plot
        field[b_x][b_y]='b';
        //test
        //print();
        if(black_win())
        {
            printf("NO\n");
            continue;
        }
        field[b_x][b_y]=0;

        int dx[4]={1,0,-1,0};
        int dy[4]={0,1,0,-1};
        bool Black_Servive=false;
        for(int i=0;i<4;i++)
        {
            //更新画图
            int nx=b_x+dx[i];
            int ny=b_y+dy[i];
            int temp=field[nx][ny];
            field[nx][ny]='b';
           // print();
            //test

            if(!isInPalace(nx,ny))//黑方帅不再皇宫中
            {
                //continue 之前要还原图
                field[nx][ny]=temp;
                continue;
            }
            else if(!catched_by(Red,nx,ny))
            {
                Black_Servive=true;
                break;
            }
            //还原画图
            field[nx][ny]=temp;

        }
        if(Black_Servive)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值