习题4-1 象棋 uva1589

算法竞赛入门经典(第2版)第4章 函数和递归

题4-1象棋  UVa1589

感悟。

1、阅读书中题目,从网站下载英文原题,重点在看输出数据与格式。

2、老外没下过象棋,是很难短时间内弄懂题意的,感觉是一道出口转内销的问题。

3、读完题,第一直觉,要用二维数组

4、对照书中中文,才明白has delivered a check意思是已经将军,还好看到这句,不然要花一定量的精力去处理是否将军。

5、基本思路是确定红方棋子管辖的范围,黑方棋子下一步移动的范围,若黑方范围为红方子集,则将死。

6、开始编写代码,突然想到黑方能将红方的棋子吃掉,这增加了编程的难度。

7、char name;scanf("%c",&name);无法读取单个字符,改成char c;char name[5];scanf("%s",name);c=name[0];成功。

8、红棋每个角色编写相关管辖范围,是本题的核心,考虑到黑棋能将红棋吃掉的情况,编写程序,样例通过,提交WA,猜测格式问题。

9、用了一组牛叉的测试数据,找到了错误,编程的时候都想到了,但写的时候没写上,确实是出现在吃子上,修改提交AC。

10、对拍掌握得更熟练了,关键还要有测试数据,详见http://tieba.baidu.com/p/3680935088其中rand测试数据得编写。

11、如上所说,提供一组测试数据:

3 1 6

G 8 5

R 2 6

R 9 6

YES

12、看看日期2016-10-30,准备第二天研究10、提到得测试数据的写法。

13、看起来不可能完成任务,AC了,信心大增数据是程序的核心。

14、如期研究了测试数据的编写,看懂了大概,但很多细节还有问题,慢慢研究。

AC代码如下,编译环境Dev-C++4.9.9.2

#include <stdio.h>
#include <string.h>

struct piece{
    char name;
    int row;
    int col;
    int live;
}red[10],redbak[10];


int board[13][13];//棋盘,只标记red棋子位置
int book[13][13];//标记red棋子管辖范围
int boardbak[13][13];//棋盘备份

void printinfo(){
    int i,j;
    for(i=1;i<=10;i++){
        for(j=1;j<=9;j++){
            printf("%d ",board[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
    
    for(i=1;i<=10;i++){
        for(j=1;j<=9;j++){
            printf("%d ",book[i][j]);
        }
        printf("\n");
    }
}
//处理管辖棋盘范围,比处理管辖皇宫范围要简单一些。
 
void general(int row,int col){//红棋general管辖范围
    int i;
    
    for(i=row-1;i>=1;i--){
        if(board[i][col]==0){
            if(i<=3&&i>=1)
                book[i][col]=1;
        }else//else跟随最近的if,这是个比较难找的错误
            break;
    }
}

void chariot(int row,int col){//管辖棋盘范围
    int i;
    for(i=row-1;i>=1;i--){//行处理,靠近上边界
        if(board[i][col]==0)
            book[i][col]=1;
        else
            break;
    }
    for(i=row+1;i<=10;i++){//行处理,靠近下边界
        if(board[i][col]==0)
            book[i][col]=1;
        else
            break;
    }
    
    for(i=col+1;i<=9;i++){//列处理,靠近右边界
        if(board[row][i]==0)
            book[row][i]=1;
        else
            break;
    }
    for(i=col-1;i>=1;i--){//列处理,靠近左边界
        if(board[row][i]==0)
            book[row][i]=1;
        else
            break;
    }
}
void cannon(int row,int col){//炮管辖棋盘范围
    int i;
    int flag;
    //架炮
    
    flag=0;
    for(i=row-1;i>=1;i--){//上方处理
        if(flag){
            if(board[i][col]==0)
                book[i][col]=1;
            else
                break;
        }
        if(flag==0&&board[i][col]==1)
            flag=1;
         
    }
    
    flag=0;
    for(i=row+1;i<=10;i++){//下方处理
        if(flag){
            if(board[i][col]==0)
                book[i][col]=1;
            else
                break;
        }
        if(flag==0&&board[i][col]==1)
            flag=1;
    }
    
    flag=0;
    for(i=col-1;i>=1;i--){//左方处理
        if(flag){
            if(board[row][i]==0)
                book[row][i]=1;
            else
                break;
        }
        if(flag==0&&board[row][i]==1)
            flag=1;
    }
    
    flag=0;
    for(i=col+1;i<=9;i++){//右方处理
        if(flag){
            if(board[row][i]==0)
                book[row][i]=1;
            else
                break;
        }
        if(flag=0&&board[row][i]==1)
            flag=1;
    }
}
void horse(int row,int col){//马管辖棋盘范围
    //以管辖位置是否存在进行处理,越界问题就容易了
    
    //竖线上有无马脚判断
    if(row-2>=1&&col-1>=1){//左上角
        if(board[row-1][col]==0)
            book[row-2][col-1]=1;
    }
    if(row-2>=1&&col+1<=9){//右上角
        if(board[row-1][col]==0)
            book[row-2][col+1]=1;
    }
    if(row+2<=10&&col-1>=1){//左下角
        if(board[row+1][col]==0)
            book[row+2][col-1]=1;
    }
    if(row+2<=10&&col+1<=9){//右下角
        if(board[row+1][col]==0)
            book[row+2][col+1]=1;
    }
    
    //横线上有无马脚判断
    if(row-1>=1&&col-2>=1){//左上角
        if(board[row][col-1]==0)
            book[row-1][col-2]=1;
    }
    if(row+1<=10&&col-2>=1){//左下角
        if(board[row][col-1]==0)
            book[row+1][col-2]=1;
    }
    if(row-1>=1&&col+2<=10){//右上角
        if(board[row][col+1]==0)
            book[row-1][col+2]=1;
    }
    if(row+1<=10&&col+2<=9){//右下角
        if(board[row][col+1]==0)
            book[row+1][col+2]=1;
    }
}

int check(int newbr,int newbc,int n){//是否将军
    int i;
    for(i=0;i<n;i++)
        if(red[i].row==newbr&&red[i].col==newbc){
            red[i].live=0;
            board[newbr][newbc]=0;//忘记清除棋盘被吃子的标识,忘记加上此句了。2016-10-30
        }
    for(i=0;i<n;i++)
        if(red[i].live==1){
            switch(red[i].name){
                case 'G':
                    general(red[i].row,red[i].col);
                    break;
                case 'R':
                    chariot(red[i].row,red[i].col);
                    break;
                case 'H':
                    horse(red[i].row,red[i].col);
                    break;
                case 'C':
                    cannon(red[i].row,red[i].col);
                    break;
            }
        }
    if(book[newbr][newbc]==1)
        return 1;
    else
        return 0;
        
}


int main(){
    int n,br,bc;
    char name[5];
    int i;
    int ans;
    int res;
    while(scanf("%d%d%d",&n,&br,&bc)==3&&n&&br&&bc){
        ans=1;
        memset(board,0,sizeof(board));
        memset(red,0,sizeof(red));
        for(i=0;i<n;i++){
            scanf("%s%d%d",name,&(red[i].row),&(red[i].col));
            red[i].name=name[0];
            red[i].live=1;
            board[red[i].row][red[i].col]=1;//标记棋盘落子位置
        }       
        
        memcpy(boardbak,board,sizeof(board));
        memcpy(redbak,red,sizeof(red));
        memset(book,0,sizeof(book));
        //black general moving like horse
        
        if(br-1>=1){//上移处理
            res=check(br-1,bc,n);
            ans*=res;
//            printf("上%d\n",res);
        }
        
        memcpy(board,boardbak,sizeof(boardbak));
        memcpy(red,redbak,sizeof(redbak));
        memset(book,0,sizeof(book));
        if(br+1<=3){//下移处理
            res=check(br+1,bc,n);
            ans*=res;
//            printf("下%d\n",res);
        }
        
        memcpy(board,boardbak,sizeof(boardbak));
        memcpy(red,redbak,sizeof(redbak));
        memset(book,0,sizeof(book));
        if(bc-1>=4){//左移处理
            res=check(br,bc-1,n);
            ans*=res;
//            printf("左%d\n",res);
        }
        
        memcpy(board,boardbak,sizeof(boardbak));
        memcpy(red,redbak,sizeof(redbak));
        memset(book,0,sizeof(book));
        if(bc+1<=6){//右移处理
            res=check(br,bc+1,n);//出现了笔误,将bc+1写成bc-1
            ans*=res;
//            printf("右%d\n",res);
        }
        
        
        if(ans==0)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}

15、附上测试数据生成程序,来自http://tieba.baidu.com/p/3680935088,程序相关地方进行了本人的注释,但未完全看懂。

程序在Dev-C++4.9.9.2环境下运行通过。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
using namespace std;


int main()
{
    freopen("rand.in", "w", stdout);
    srand(unsigned(time(0)));
    int maxn = 6, count = 0;
    int dir[11][10];
    const char s0[] = "RRCCHH";
    for (int s = (1<<maxn) - 1; s >= 1; s--)
        for (int num = 1000; num; num--)
        {
            memset(dir, 0, sizeof(dir));
            int n = 0, is = 0;
            int r0 = 1 + rand() % 3, c0 = 4 + rand() % 3;//黑棋将的位置
            dir[r0][c0] = 1;
            int r1 = 8 + rand() % 3, c1 = 4 + rand() % 3;//红棋将的位置
            while (c0 == c1)//目的是使黑红两将不在同一竖直位置
                c1 = 4 + rand() % 3;
            dir[r1][c1] = 1;
            for (int i = 0; i < maxn; i++)//n值从6至1开始变化
                if (s & (1<<i))
                    n++;
            printf("\n%d %d %d\nG %d %d\n",n + 1, r0, c0, r1, c1);//打印第一行,第二行
            count++;
            for (int i = 0; i < maxn; i++)
            if (s & (1<<i))
            {
                int r = 1 + rand() % 10, c = 1 + rand() % 9;//车马炮位置
                if (is == 0 && s0[i] != 'C')
                {
                    if (s0[i] != 'H')//车
                    {
                        r = r0 + 1;
                        c = c0;
                        //printf("车%c\n",s0[i]);
                    }
                    else//马
                    {
                        r = r0 + 2;
                        c = c0 + 1;
                        //printf("马%c\n",s0[i]);
                    }
                    is = 1;
            }
            else//炮车马
            {
                while (dir[r][c])
                {
                    r = 1 + rand() % 10;
                    c = 1 + rand() % 9;
                }
                //printf("炮车马%c\n",s0[i]);
            }
            dir[r][c] = 1;
            printf("%c %d %d\n", s0[i], r, c);
        }
    }
    printf("0 0 0\n");
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值