中国象棋将帅问题

    xiaoxiao2021-03-25  128

    中国象棋将帅问题

    分析与解法:

    程序的大体框架: 1.遍历 A 的位置 2. 遍历 B 的位置 3. 判断 A 、 B 的位置组合是否满足要求 如果满足,则输出。

    类似于双层循环运算

    创建一个逻辑坐标系统,用 1-9 的数字,按照行优先的顺序来表示每个格点的位置。

    关键问题在于只使用一个变量来表示A和B的位置。所以可以使用位运算来解决。一个无符号字符类型的长度是1字节,也就是8位,8位可以表示2^8=256个值,对于A、B的9个位置来说足够。可以用前4位来表示A的位置情况,后4位表示B的位置情况。而4位可以表示16个数也足够表示A、B的位置情况了。 解法一给出的方法是将一个Byte变量拆成两个用,前一半代表“帅”可以走的位置,后一个变量代表“将”可以走的位置(事先已经将“将”和“帅”可以走的3*3的位置进行了编号),利用位操作即可获得两个计数器的功能。

    通过位运算可以对A、B的位置进行读取和修改。 几种基本的位运算: (1)& 按位与运算 (2)| 按位或运算 “与”和”或”就不用说了吧 (3)^ 按位异或运算 相同为假,不同为真 (4)~ 按位取反 一元运算符 (5)<< 按位左移 如 0000 0111 << 2 = 0001 1100,将此数左移两位相当于将此数扩大两倍。 (6)>> 按位右移 如 0001 1000 >> 2 = 0000 0110,将此数右移两位相当于将此数缩小两倍。 令LMASK为1111 0000,另任意一个1字节的字符型变量与其做与运算,结果右移四位,便可得到此变量的高四位的值。 Example, 0110 1011 &1111 0000 = 0110 0000 >> 4 = 0000 0110 同理,令RMASK为0000 1111,即可得到它低四位的值。 Ex. 0110 1011 & 0000 1111 = 0000 1011 设置1字节字符型变量,比如对高四位进行设置,先将变量与RMASK相与,将要修改的变量左移四位后于前一结果进行“异或”或“或运算”。 Ex.将0110 1011高四位设置为1001. 0110 1011 & 0000 1111 = 0000 1011 0000 1001 << 4 = 1001 0000 ^ 1001 0000 = 1001 1011 同样的方法设置低四位的值。

    解法1: 代码:

    #include <stdio.h> #include <iostream> #define HALF_BITS_LENGTH 4 //这个值是记忆存储单元长度的一半,在这道题里是4bit #define FULLMASK 255 //这个数字表示一个全部bit的mask,在二进制表示中,它表示11111111. #define LMASK (FULLMASK<<HALF_BITS_LENGTH) //这个数字表示左bits的mask,在二进制表示中,它是11110000. #define RMASK (FULLMASK>>HALF_BITS_LENGTH) //这个数字表示右bits的mask,在二进制表示中,它是00001111. #define LSET(b,n) (b=(RMASK&b)|((n)<<HALF_BITS_LENGTH)) //这个宏,将b的左边设置成n #define LGET(b) ((b&LMASK)>>HALF_BITS_LENGTH) //这个宏,得到左边的值 #define RSET(b,n) (b=((LMASK&b)|(n))) //这个宏,将b的右边设置成n #define RGET(b) (RMASK&b) #define GRIDW 3//这个数字表示将帅移动范围的行宽度 using namespace std; int main () { unsigned char b; for (RSET(b,1);RGET(b)<=GRIDW*GRIDW;RSET(b,(RGET(b)+1))) for(LSET(b,1);LGET(b)<=GRIDW*GRIDW;LSET(b,(LGET(b)+1))) if((LGET(b)%GRIDW)!=(RGET(b)%GRIDW)) cout<<"A= "<<RGET(b)<<" B= "<<LGET(b)<<"\t"; cin.get(); return 0; }

    输出:

    解法2: 用到了 C 语言的 struct 结构,原理和解法1类似 其中unsigned char a:4表示结构体中a的位域只有4位,高位用作它用。只能在结构体里使用,建议尽量少用,会破坏程序的移植性。 当结构体中的元素的取值范围很小时,可以将几个字段按位合成一个字段来表示,起到节省内存空间的作用。 代码:

    #include <stdlib.h> #include <iostream> using namespace std; struct{ unsigned char a:4; unsigned char b:4; }i;//一个struct类型占用一个字节 int main() { 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) cout<<"A= "<<int(i.a)<<" B= "<<int(i.b)<<"\t";//需将char型转化为int型 //printf("A = %d, B = %d\n", i.a, i.b); cout<<endl<<sizeof(i); cin.get(); return 0; }

    输出:

    解法3: 可以把变量i想象成一个两位九进制的变量,而i在计算机中存储的值是i的十进制表示。则i/9的计算机处理结果,即结果直接去掉小数点后部分的结果即是此九进制数的第二位,而i%9即是此九进制数的个位。本程序用此九进制数的第二位保存A的位置,个位表示B的位置。九进制00-88对应十进制00-80。我们共需要验证9*9=81种位置关系,这也是i=81的由来。此外我们要明白i/9和i%9的含义。我们知道,整数i可以由部两分组成,即var=(var/9)*9+var%9 ,其中var

    #include <iostream> //#define BYTE unsigned char typedef unsigned char BYTE; using namespace std; int main() { BYTE i=81; while(i--) { if(i/9%3!=(i%9%3)) cout<<"A= "<<i/9+1<<" B= "<<i%9+1<<"\t"; } cin.get(); return 0; }

    输出:

    参考:http://blog.csdn.net/kabini/article/details/2256421

    转载请注明原文地址: https://ju.6miu.com/read-25752.html

    最新回复(0)