HDU 4121 Xiangqi

来源:互联网 发布:巴拉密 知乎 编辑:程序博客网 时间:2024/05/16 02:06

Xiangqi

   Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
  Total Submission(s): 3516    Accepted Submission(s): 852


Problem Description
Xiangqi is one of the most popular two-player board games in China. The game represents a battle between two armies with the goal of capturing the enemy’s “general” piece. In this problem, you are given a situation of later stage in the game. Besides, the red side has already “delivered a check”. Your work is to check whether the situation is “checkmate”.

Now we introduce some basic rules of Xiangqi. Xiangqi is played on a 10×9 board and the pieces are placed on the intersections (points). The top left point is (1,1) and the bottom right point is (10,9). There are two groups of pieces marked by black or red Chinese characters, belonging to the two players separately. During the game, each player in turn moves one piece from the point it occupies to another point. No two pieces can occupy the same point at the same time. A piece can be moved onto a point occupied by an enemy piece, in which case the enemy piece is "captured" and removed from the board. When the general is in danger of being captured by the enemy player on the enemy player’s next move, the enemy player is said to have "delivered a check". If the general's player can make no move to prevent the general's capture by next enemy move, the situation is called “checkmate”.

We only use 4 kinds of pieces introducing as follows:
General: the generals can move and capture one point either vertically or horizontally and cannot leave the “palace” unless the situation called “flying general” (see the figure above). “Flying general” means that one general can “fly” across the board to capture the enemy general if they stand on the same line without intervening pieces.
Chariot: the chariots can move and capture vertically and horizontally by any distance, but may not jump over intervening pieces
Cannon: the cannons move like the chariots, horizontally and vertically, but capture by jumping exactly one piece (whether it is friendly or enemy) over to its target.
Horse: the horses have 8 kinds of jumps to move and capture shown in the left figure. However, if there is any pieces lying on a point away from the horse horizontally or vertically it cannot move or capture in that direction (see the figure below), which is called “hobbling the horse’s leg”.



Now you are given a situation only containing a black general, a red general and several red chariots, cannons and horses, and the red side has delivered a check. Now it turns to black side’s move. Your job is to determine that whether this situation is “checkmate”.
 

Input
The input contains no more than 40 test cases. For each test case, the first line contains three integers representing the number of red pieces N (2<=N<=7) and the position of the black general. The following n lines contain details of N red pieces. For each line, there are a char and two integers representing the type and position of the piece (type char ‘G’ for general, ‘R’ for chariot, ‘H’ for horse and ‘C’ for cannon). We guarantee that the situation is legal and the red side has delivered the check.
There is a blank line between two test cases. The input ends by 0 0 0.
 

Output
For each test case, if the situation is checkmate, output a single word ‘YES’, otherwise output the word ‘NO’.
 

Sample Input
2 1 4G 10 5R 6 43 1 5H 4 5G 10 5C 7 50 0 0
 

Sample Output
YESNO
Hint
In the first situation, the black general is checked by chariot and “flying general”.In the second situation, the black general can move to (1, 4) or (1, 6) to stop check. See the figure above.
 

Source
2011 Asia Fuzhou Regional Contest
 



题目链接  :http://acm.hdu.edu.cn/showproblem.php?pid=4121


题目大意 :会下象棋的一下就知道题目是要干嘛了,就是红棋在将军的情况下问能不能将死。保证黑方只有一颗棋子就是将,红方至少有一个帅和几个车,马或者炮总数小于等于7大于等于2 (2<=N<=7),在这给不会下象棋的说下走棋规则:

1.车可以水平走或者竖直走任意格,前提是没有别的棋子挡在车的路线上
2.炮打隔子,就是说炮只能隔着某个棋子攻击其后面的棋子,路线必须是水平或者竖直
3.马走日,马只能沿着日子的对角线跳,并且可能蹩马脚,蹩马脚就不能跳了,就是上图那个马棋子画叉的情况
 4.若是将走,走完之后正对帅,即将和帅的连线上没有别的棋子,则将被帅kill反之同理
  5.若是黑方的棋子覆盖在红方棋子上,则当做黑方kill了红方一个棋子,红方该棋子移出棋盘。反之同理
  6.将和帅的活动范围很小,只能在那个田字格里


题目分析 :典型的大模拟,博主在网上也看了别人的代码很多100+的很厉害,博主思路很裸,200+的模拟,思路很简单,以将为中心往四个方向走(如果能走),如果四个方向有一个方向不被kill则判为将不死,每个方向上分别枚举车马炮帅四类棋能不能将军的情况


15ms代码 
#include <cstdio>#include <cstring>#include <iostream>using namespace std;char map[11][10];struct Piece{    char type;    int x, y;}p[7];//判断将左边是否有车能kill将bool IsRcheckl(int gx, int gy){   for(int j = gy - 1; j >= 1; j--)   {        //棋盘点值为0表示该点没棋子,则继续找        if(map[gx][j] == 0)            continue;        //有棋子但不是车返回false        if(map[gx][j] != 0 && map[gx][j] != 'R')            return false;        if(map[gx][j] == 'R')            return true;   }   return false;  //若该方向没棋子返回false}//判断将右边是否有车能kill它bool IsRcheckr(int gx, int gy){   for(int j = gy + 1; j <= 9; j++)   {        if(map[gx][j] == 0)            continue;        if(map[gx][j] != 0 && map[gx][j] != 'R')            return false;        if(map[gx][j] == 'R')            return true;   }   return false;}//判断将下边是否有车能kill它bool IsRcheckd(int gx, int gy){    for(int i = gx + 1; i <= 10; i++)    {        if(map[i][gy] == 0)            continue;        if(map[i][gy] != 0 && map[i][gy] != 'R')            return false;        if(map[i][gy] == 'R')            return true;    }    return false;}//判断将上边是否有车能kill它bool IsRchecku(int gx, int gy){   for(int i = gx - 1; i >= 1; i--)   {        if(map[i][gy] == 0)            continue;        if(map[i][gy] != 0 && map[i][gy] != 'R')            return false;        if(map[i][gy] == 'R')            return true;   }   return false;}//判断将周围是否有能将其kill的马bool IsHcheck(int gx, int gy){    //马首先要在棋盘范围内且被蹩脚不能跳,这里是以将为中心枚举8个方向的马    if(gx - 2 >= 1 && map[gx - 2][gy - 1] == 'H' && map[gx - 1][gy - 1] == 0)        return true;    if(gx - 1 >= 1 && map[gx - 1][gy - 2] == 'H' && map[gx - 1][gy - 1] == 0)        return true;    if(map[gx + 1][gy - 2] == 'H' && map[gx + 1][gy - 1] == 0)        return true;    if(map[gx + 2][gy - 1] == 'H' && map[gx + 1][gy - 1] == 0)        return true;    if(map[gx + 2][gy + 1] == 'H' && map[gx + 1][gy + 1] == 0)        return true;    if(map[gx + 1][gy + 2] == 'H' && map[gx + 1][gy + 1] == 0)        return true;    if(gx - 1 >= 1 && map[gx - 1][gy + 2] == 'H' && map[gx - 1][gy + 1] == 0)        return true;    if(gx - 2 >= 1 && map[gx - 2][gy + 1] == 'H' && map[gx - 1][gy + 1] == 0)        return true;    return false;//若都kill不了返回false}//判断将左边是否有炮能kill它bool IsCcheckl(int gx, int gy){    int count = 0;    //炮隔子打,当count等于2且该棋子不为炮则返回false    //否则返回true    for(int j = gy - 1; j >= 1; j--)    {        if(map[gx][j] == 0)            continue;        if(map[gx][j] != 0)            count++;        if(count == 2)        {            if(map[gx][j] == 'C')                return true;            else                return false;        }    }    return false;//若该方向无棋子返回false}//判断将右边是否有炮能kill它bool IsCcheckr(int gx, int gy){    int count = 0;    for(int j = gy + 1; j <= 9; j++)    {        if(map[gx][j] == 0)            continue;        if(map[gx][j] != 0)            count++;        if(count == 2)        {            if(map[gx][j] == 'C')                return true;            else                return false;        }    }    return false;}//判断将下边是否有炮能kill它bool IsCcheckd(int gx, int gy){    int count = 0;    for(int i = gx + 1; i <= 10; i++)    {        if(map[i][gy] == 0)            continue;        if(map[i][gy] != 0)            count++;        if(count == 2)        {            if(map[i][gy] == 'C')                return true;            else                return false;        }    }    return false;}//上面炮不用判断在将上面的情况因为不可能//判断将下边是否有帅能kill它bool IsGcheck(int gx, int gy){    for(int i = gx + 1; i <= 10; i++)    {        if(map[i][gy] == 0)            continue;        if(map[i][gy] != 0 && map[i][gy] != 'G')            return false;        if(map[i][gy] == 'G')            return true;    }    return false;}bool IsCheckmate(int gx, int gy){    bool flag1, flag2, flag3, flag4; //四个flag表示4个方向    //这里true表示将不能走,因为将不能出棋盘,所以当将往某个方向不可行的话    //值就为true,所以干脆全初始化为true    flag1 = flag2 = flag3 = flag4 = true;    //以下枚举四个方向和9种可能,只要有一个满足,将就不能往该方向走    if(gx + 1 <= 3)    {        //这里一定要注意!将走完要还原棋盘!        char temp = map[gx + 1][gy];        map[gx + 1][gy] = '*';        map[gx][gy] = 0;        if(IsCcheckd(gx + 1, gy) || IsCcheckl(gx + 1, gy) || IsCcheckr(gx + 1, gy)           || IsHcheck(gx + 1, gy) || IsGcheck(gx + 1, gy) || IsRcheckd(gx + 1, gy)           || IsRchecku(gx + 1, gy) || IsRcheckl(gx + 1, gy) || IsRcheckr(gx + 1, gy))            flag1 = true;        else            flag1 = false;        map[gx + 1][gy] = temp;        map[gx][gy] = '*';    }    if(gx - 1 >= 1)    {        char temp = map[gx - 1][gy];        map[gx - 1][gy] = '*';        map[gx][gy] = 0;        if(IsCcheckd(gx - 1, gy) || IsCcheckl(gx - 1, gy) || IsCcheckr(gx - 1, gy)            || IsHcheck(gx - 1, gy) || IsGcheck(gx - 1, gy) || IsRcheckd(gx - 1, gy)            || IsRchecku(gx - 1, gy) || IsRcheckl(gx - 1, gy) || IsRcheckr(gx - 1, gy))            flag2 = true;        else            flag2 = false;        map[gx - 1][gy] = temp;        map[gx][gy] = '*';    }    if(gy + 1 <= 6)    {        char temp = map[gx][gy + 1];        map[gx][gy + 1] = '*';        map[gx][gy] = 0;        if(IsCcheckd(gx, gy + 1) || IsCcheckl(gx, gy + 1) || IsCcheckr(gx, gy + 1)            || IsHcheck(gx, gy + 1) || IsGcheck(gx, gy + 1) || IsRcheckd(gx, gy + 1)            || IsRchecku(gx, gy + 1) || IsRcheckl(gx, gy + 1) || IsRcheckr(gx, gy + 1))            flag3 = true;        else            flag3 = false;        map[gx][gy + 1] = temp;        map[gx][gy] = '*';    }    if(gy - 1 >= 4)    {        char temp = map[gx][gy - 1];        map[gx][gy - 1] = '*';        map[gx][gy] = 0;        if(IsCcheckd(gx, gy - 1) || IsCcheckl(gx, gy - 1) || IsCcheckr(gx, gy - 1)            || IsHcheck(gx, gy - 1) || IsGcheck(gx, gy - 1) || IsRcheckd(gx, gy - 1)            || IsRchecku(gx, gy - 1) || IsRcheckl(gx, gy - 1) || IsRcheckr(gx, gy - 1))            flag4 = true;        else            flag4 = false;        map[gx][gy - 1] = temp;        map[gx][gy] = '*';    }    //printf("%d %d %d %d\n",flag1, flag2, flag3, flag4);    //如果四个方向将都不能走,则说明被将死    if(flag1 && flag2 && flag3 && flag4)        return true;    return false;}int main(){    int n, gx, gy;    while(cin >> n >> gx >> gy && (n + gx + gy))    {        memset(p,0,sizeof(p));        memset(map,0,sizeof(map));        map[gx][gy] = '*';             //当前将的位置        for(int i = 0; i < n; i++)     //输入红棋信息        {            cin >> p[i].type >> p[i].x >> p[i].y;            map[p[i].x][p[i].y] = p[i].type;        }        if(IsCheckmate(gx, gy)) //如果被将死,输出YES            printf("YES\n");        else            printf("NO\n");    }}



0 0