中国象棋将帅问题

写一个虽然没什么难度,但看书看到了的题。
题目如下:



可以看出,此题不难,最简单的方法就是遍历了,当我们首先遍历“将”的位置,再遍历“帅”的位置,然后判定当前位置是否满足题意,即有效,即可!但是关键点在于最后一句话,要求代码中只能使用一个字节存储变量。我们都知道,一个字节也就是一个bit,8位。那么从这里出发,可以看出考题人用意在于考察位运算的掌握程度。
所以,我主要说一下位运算:

含义 Pascal语言 C语言 C#语言 Java
按位与 a and b a & b a & b a & b
按位或 a or b a | b a | b a | b
按位异或 a xor b a ^ b a ^ b a ^ b
按位取反 not a ~a ~a ~a
左移 a shl b a << b a << b a << b
带符号右移 a shr b a >> b a >> b a >> b
无符号右移 a>>> b

主要常用的有三种(其中“非”没讲,即按位取反):


00101
11100
(&;或者and)
—————
00100

00101
11100
(|或者or)
—————
11101
异或
00101
11100
(^或者xor)
—————-
11001

接下来讲一下题解:
我们按照一个bit数来看的话,四位即二进制的1111可以表示到十进制数15,所以我们可以按照前四位与后四位的数来表示(unsigned char),然后通过对其位操作,改变其数值大小,最后检查位置的有效性,输出即可;
能表示的位置,我们假设成如下图

代码如下:

#include 

using namespace std;

//表示一个bit的一般长度(一个bit 8位)
#define HALF_BIT_LENGTH 4

//表示一个bit的全码即二进制表示为 11111111
#define FULLMASK 255

//表示一个bit的前四位的全码,即 11110000
#define LMASK (FULLMASK << HALF_BIT_LENGTH)

//表示一个bit的后四位的全码, 即 00001111
#define RMASK (FULLMASK >> HALF_BIT_LENGTH)

//设置前四位为n
#define LSET(num, n) (num = (num & RMASK) | (n << HALF_BIT_LENGTH))

//设置后四位为n
#define RSET(num, n) (num = (num & LMASK) | n)

//获取前四位的值
#define LGET(num) ((num & LMASK) >> HALF_BIT_LENGTH)

//获取后四位的值
#define RGET(num) (num & RMASK)

//定义棋子的移动范围,本题中将帅移动方阵为 3 * 3
#define MROW 3


int main(void)
{
    //定义变量,表示当前将帅的位置
    unsigned char temp;

    //初始化左节点循环
    for (LSET(temp, 1); LGET(temp) <= MROW * MROW; LSET(temp, (LGET(temp) + 1)))
    {
        //初始化右节点循环
        for (RSET(temp, 1); RGET(temp) <= MROW * MROW; RSET(temp, (RGET(temp) + 1)))
        {
            //判断当前位置是否有效
            if ((LGET(temp) % MROW) != (RGET(temp) % MROW))
            {
                //位置有效,则输出
                cout << "If A stay at " << LGET(temp) << ", B effective position is " << RGET(temp) << endl;
            }
        }
    }


    return 0;

}

结果输出如下:
中国象棋将帅问题_第1张图片

你可能感兴趣的:(编程之美)