• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
magicat
博客园    首页    新随笔    联系   管理    订阅  订阅
UVA1589 象棋 Xiangqi题解

这题考察我们的大脑体力,非常难调,我花了3.5小时,要是在区域赛里做着题,我碰都不碰,没有大样例非常难受。

分析如下:

  • 中国象棋,见百度百科
  • 就是考虑当前情况下将军是不是已经给将死了

考虑:

  1. 飞将
  2. 将军吃掉了红色棋子的情况
  3. 马脚问题
  4. 将军只能在一定的区域内移动
  5. 注意边界情况
  6. 善用工具来debug,我用了udebug,里面有一个大样例,cmd我是可以看到输入的,但吞了我一部分输出,搞得我虚空调试,我一个一个对照才发现我代码早就是对的了,这也是教训

udebug

 

 

 

 

//  AC one more times

////////////////////////////////////////INCLUDE//////////////////////////////////////////

#include <iostream>
#include <algorithm>
#include <cstdio>
#include<string>
#include<string.h>
#include <cstring>
#include <complex>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <list>
#include <bitset>
#include <assert.h>
#include <unordered_set>
#include <unordered_map>
#include <iomanip>
#include <random>
#include <iterator>
#include <time.h>

using namespace std;
/////////////////////////////////////////DEFINE//////////////////////////////////////////

#define fi first
#define se second
#define pb push_back
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define inf64 0x3f3f3f3f3f3f3f3f

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<long long,long long> PLL;

////////////////////////////////////////CONST////////////////////////////////////////////

const int  inf = 0x3f3f3f3f;
const int maxn = 2e6 + 6;
const double eps = 1e-8;
const long long mod = 1000000;

///////////////////////////////////////FUNCTION//////////////////////////////////////////

template<typename T>
void init(T q[], int n, T val){   for (int i = 0; i <= n; i++) q[i] = val;  }
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
bool cmp(int c, int d) { return c > d; }


int n,bi,bj;

int dx[]={0,0,1,-1};            // 普通的四个方向位移
int dy[]={1,-1,0,0};

int hx[]={0, -2,-2,     -1,1,   2,2,    1,-1  };    //马的位移量
int hy[]={0, -1, 1,      2,2,   1,-1,   -2,-2 };

char op[15][15];    //最开始的棋盘

char ma [15][15];  //将军位移了的棋盘

int ans[15][15];    //将军位移的情况下,哪些地方可以吃的棋盘  1做标记

bool check1()       //检查黑将军能不能吃掉帅
{
    for(int i=bi+1;i<=10;i++)
    {
        if(op[i][bj]==' ')  continue;
        else if(op[i][bj]=='G')     return true;
        else break;
    }
    return false;
}
bool check_address(int x,int y)     //检查将军的位移是否合法
{
    if(x>=1&&x<=3&&y>=4&&y<=6)  return true;
    else return false;
}
bool check_bound(int x,int y)       //检查棋子是不是在棋盘内,位移是否合法
{
    if(x>=1&&x<=10&&y>=1&&y<=9) return true;
    else return false;
}

// 车和帅可以合并,两者有共性
void che(int x,int y)               //车四个方向一直打,直到遇到棋子和边界 
{
    for(int i=x+1;i<=10;i++)
    {
        if(ma[i][y]==' ')   ans[i][y]=1;
        else break;
    }    

    for(int i=x-1;i>=1;i--)
    {
        if(ma[i][y]==' ')   ans[i][y]=1;
        else break;
    }   
    for(int j=y+1;j<=9;j++)
    {
        if(ma[x][j]==' ')   ans[x][j]=1;
        else break;    
    }

    for(int j=y-1;j>=1;j--)
    {
        if(ma[x][j]==' ')   ans[x][j]=1;
        else break;    
    }
 


}
void pao(int x,int y)                   // 炮四个方向分别找到第一个棋子,然后一直打,知道遇到棋子和边界停下来
{
    for(int i=x+1;i<=10;i++)
        if(ma[i][y]!=' ')
        {
            for(int j=i+1;j<=10;j++)
            {
                if(ma[j][y]!=' ')   break;          // 打不了了,不打了
                ans[j][y]=1;
            }
            break;
        }
    
    for(int i=x-1;i>=1;i--)
        if(ma[i][y]!=' ')
        {
            for(int j=i-1;j>=1;j--)
            {
                if(ma[j][y]!=' ')   break;          // 打不了了,不打了
                ans[j][y]=1;
            }
            break;
        }
    

    for(int j=y+1;j<=9;j++)
        if(ma[x][j]!=' ')
        {
            for(int i=j+1;i<=9;i++)
            {            
                if(ma[x][i]!=' ')   break;          // 打不了了,不打了   
                ans[x][i]=1;
            }
            
            break;
        }
    
    for(int j=y-1;j>=1;j--)
        if(ma[x][j]!=' ')
        {
            for(int i=j-1;i>=1;i--)
            {            
                if(ma[x][i]!=' ')   break;          // 打不了了,不打了   
                ans[x][i]=1;
            }
            break;
        }
}


void maa(int x,int y,int k)                     // 马这里算了四个情况来考虑马给卡脚的情况,我看也向是四个方向
{
    // k代表方向
    if(k==1)                    
    {
        if(ma[x-1][y]==' '&&check_bound(x-1,y))     //检查是是否卡马脚,和位移是否合法
            for(int m=1;m<=2;m++)
            {
                int tx=x+hx[m],ty=y+hy[m];
                if(check_bound(tx,ty)==true&&ma[tx][ty]==' ')
                    ans[tx][ty]=1;
            }
    }
    else if(k==2)
    {
        if(ma[x][y+1]==' '&&check_bound(x,y+1))     //检查是是否卡马脚,和位移是否合法
        {
            for(int m=3;m<=4;m++)
            {
                int tx=x+hx[m],ty=y+hy[m];
                if(check_bound(tx,ty)==true&&ma[tx][ty]==' ')
                    ans[tx][ty]=1;
            }
        }
    }
    else if(k==3)
    {
        if(ma[x+1][y]==' '&&check_bound(x+1,y))     //检查是是否卡马脚,和位移是否合法
        {
            for(int m=5;m<=6;m++)
            {
                int tx=x+hx[m],ty=y+hy[m];
                if(check_bound(tx,ty)==true&&ma[tx][ty]==' ')
                    ans[tx][ty]=1;    
            }
        }
    }
    else if(k==4)
    {
        if(ma[x][y-1]==' '&&check_bound(x,y-1))     //检查是是否卡马脚,和位移是否合法
        {
            for(int m=7;m<=8;m++)
            {
                int tx=x+hx[m],ty=y+hy[m];
                if(check_bound(tx,ty)==true&&ma[tx][ty]==' ')
                    ans[tx][ty]=1;    
            }
        }
    }



}
void solve()
{
    memset(op,' ',sizeof op);
    //存点    最开始的棋盘
    for(int i=1;i<=n;i++)
    {
        char c; int x,y;    cin>>c>>x>>y;
        op[x][y]=c;
    }

    //  飞将的判断
    bool check = false ;
    check=check1();
    if(check==true)   
    {    
        cout<<"NO"<<endl;
        return;
    }

    int sum1=0;
    //枚举将军的能到达的点
    for(int m=0;m<=3;m++)
    {
        int x=bi+dx[m],y=bj+dy[m];
        if(check_address(x,y)==false)   continue;       //将位移的合法性

        sum1++;
        //复制一份地图, 在将位移可能吃掉红子
        memset(ma,' ',sizeof ma);
        for(int i=1;i<=10;i++)
            for(int j=1;j<=9;j++)
                if(i==x&&j==y)  continue;
                else ma[i][j]=op[i][j];

        //枚举红方的棋子,哪些地方会被吃
        //ans 来记录
        memset(ans,0,sizeof ans);       //将“将军位移的情况下,哪些地方可以吃的棋盘  1做标记”的数组全计为0

        for(int i=1;i<=10;i++)
        {
            for(int j=1;j<=9;j++)
            {
                if(ma[i][j]=='R')
                    che(i,j);           //车
                else if(ma[i][j]=='C')
                    pao(i,j);           //炮
                else if(ma[i][j]=='H')
                {
                    for(int k=1;k<=4;k++)
                    {
                        maa(i,j,k);     //马
                    }
                }
                else if(ma[i][j]=='G')
                {
                    che(i,j);           //帅       
                }
            }
        }

        //输出可以吃的地图检查
        /*
        for(int i=1;i<=10;i++)
        {
            for(int j=1;j<=9;j++)
            {
                cout<<ans[i][j];
            }
            cout<<endl;
        }
        cout<<endl;
        cout<<endl;

        
        cout<<m<<" "<<sum1<<endl;
        */

        if(ans[x][y]==1)
            sum1--;
    }
    //sum1 代表将军可以走到的点的数量,当走到的点会给吃就--,当sum=0说明无路可走
    if(sum1==0)
        cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return;
}
int main()
{
    std::ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    while(cin>>n>>bi>>bj)
    {
        if(n==0&&bi==0&&bj==0)  return 0;
        solve();
    }    
    return 0;
    
}

 

本文来自博客园,作者:magicat,转载请注明原文链接:https://www.cnblogs.com/magicat/p/16301119.html

posted on 2022-05-23 14:36  magicat  阅读(78)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3