【编程之美 】-中国象棋将帅问题

【描述】《编程之美》上的此问题是有一定限制的:把“将”和“帅”限制在一个3*3的网格中,那么根据规则是“将”和“帅”是不能同在一条竖线的位置,求出所有符合条件的“将”和“帅”的位置,并且只用一个变量来储存。
这里写图片描述
【思路】书上给出了几个解答:
(1)第一个答案用二进制来表示,稍微有点复杂:一个8位的byte类型能够表达2^8=256个值,所以用它来表示A,B的位置信息绰绰有余,因此可以把字节的变量(设为b)分成两部分,用前面的4bit表示A的位置,用后面的4bit表示B的位置,那么4个bit可以表示16个数,这已经足够。然后前后4位分开进行处理,下面的做法是把一个char变量(8位)分成上四位和下四位,上四位表示A的位置,下四位表示B的位置:
代码:

#include <stdio.h>
#define HALF_BITS_LENGTH 4//这个值是记忆存储单元长度的一般,在这道题里是4bit;
#define FULLMASK 255//这个数字表示一个全部bit的mask,在二进制表示中,它是11111111
#define LMASK (FULLMASK<<HALF_BITS_LENGTH)
//这个宏表示一个左bit的mask,在二进制表示中,它是11110000、用宏的时候如果里面有运算符,记得加括号
#define RMASK (FULLMASK>>HALF_BITS_LENGTH)//这个宏表示一个左bit的mask,在二进制表示中,它是00001111、
#define RSET(b,n) (b=((LMASK&b)^n))//这个宏将b的右边设置成n;
#define LSET(b,n) (b=((RMASK&b)^(n<<HALF_BITS_LENGTH)))//这个宏,将b的左边设置成n;
#define RGET(b) (RMASK&b)//这个宏得到b右边的值;
#define LGET(b) ((LMASK&b)>>HALF_BITS_LENGTH)//这个宏得到b左边的值;
#define GRIDW 3
//grid的宽度,
//以上的作为给我们封装数据结构提供了另外一种思路——使用宏定义
//以上的宏定义设置了一个数据结构,这个数据结构的变量为一个BITE,
//操作为对左半部分赋值和右半部分赋值,以及分别获得左右两部分的值;
//这里用了抽象和分层设计其中RSET LSET RGET LGET GRIDW直接作为应用宏供调用
//LMASK RMASK  为抽象出来的第二层宏,FULLMASK和HASL_BITS_LENGTH 为底层调用。
//这个设计思路肯定是自上向下的,而不是自下向上。
int main()
{
       unsigned char b;//使用unsigned可以获取一个8位数字;
       for(LSET(b,1);LGET(b)<=GRIDW*GRIDW;LSET(b,(LGET(b)+1)))
              for(RSET(b,1);RGET(b)<=GRIDW*GRIDW;RSET(b,(RGET(b)+1)))
                     if(LGET(b)%GRIDW!=RGET(b)%GRIDW)
                        printf("A=%d,B=%d\n",LGET(b),RGET(b));

       return 0;

}

(2)把两个值的关系映射到一个坐标轴上。利用A的所有位置有9中可能,B同理,那么AB的所有可能共有9^2=81种可能,那么只要对除9对3取余判断是否不在同一列即可,C语言中可以使用unsigned char 来表示一个字节的整数,所以char型本质上也是整数类型,代码:

unsigned char  i=81;
while(i--)
{
if( (i/9%3)!=(i%9%3) )
printf("A= %d,B= %d\n",i/9+1,i%9+1);
}
return 0;

(3)字节拆分:利用了结构体共用字节的特点,代码:

struct
{
    unsigned char a:4;
    unsigned char b:4;
} i;
struct{
    int a;
    int b;
}j;
int main()
{
    /*
    printf("sizeof(i)%d\n",sizeof(i)); //输出1
    printf("sizeof(i)%d\n",sizeof(j)); //输出8
    */
    for(i.a = 1; i.a<=9; i.a++){
        for(i.b=1; i.b<=9; i.b++){
            if(i.a%3 != i.b%3){
                printf("A = %d,B= %d\n",i.a,i.b);
            }
        }
    }
    return 0;
}

【延伸】:想到如果“将”和“帅”不受限制,分别在各自地盘活动,不能越界且同样不能处在同一列的情况下共有多少种可能?
【思路】其实仔细思考一下不难得出解法只要排斥掉同一列的情况下就可以满足条件,代码:


struct node
{
    int x;
    int y;
} A,B;
int main()
{
    char mp[9]= {'a','b','c','d','e','f','g','h','i'};
    /*
    Place_Sum=45^2=2025;

    10
    9    B
    8
    7
    6

    5
    4
    3
    2
    1  A
     a b c d e f g h i
    */
    for(A.x=1; A.x<=9; ++A.x)
        for(A.y=1; A.y<=5; ++A.y)
            for(B.x=1; B.x<=9; ++B.x)
                for(B.y=1; B.y<=5; ++B.y)
                {
                    if(A.x!=B.x)
                    {
                        printf("A.x=%c A.y=%d  B.x=%c B.y=%d\n",mp[A.x-1],A.y,mp[B.x-1],B.y+5);
                    }
                }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值