中国象棋将帅问题

来源:互联网 发布:网络三大奇书之一 编辑:程序博客网 时间:2024/05/16 13:05

中国象棋将帅问题

这里写图片描述

分析与解法:

程序的大体框架:
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 chartypedef 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

0 0
原创粉丝点击