编程之美读书笔记1.2——中国象棋将帅问题
2014-07-02 10:16
381 查看
http://blog.csdn.net/pipisorry/article/details/36380669
问题:下过中国象棋的朋友都知道,双方的“将”和“帅”相隔遥远,并且它们不能照面。在象棋残局中,许多高手能利用这一规则走出精妙的杀招。假设棋盘上只有“将”和“帅”二子(如图1-3所示)(为了下面叙述方便,我们约定用A表示“将”,B表示“帅”):
A、B二子被限制在己方3×3的格子里运动。例如,在如上的表格里,A被正方形{d10, f10, d8, f8}包围,而B被正方形{d3, f3, d1, f1}包围。每一步,A、B分别可以横向或纵向移动一格,但不能沿对角线移动。另外,A不能面对B,也就是说,A和B不能处于同一纵向直线上(比如A在d10的位置,那么B就不能在d1、d2以及d3)。
请写出一个程序,输出A、B所有合法位置。要求在代码中只能使用一个变量。
分析:
题目中仅仅是要求判断将与帅是否照面,而将与帅只能在各自的9个位置移动,因而只需要形式化1~9这9个数字。
此题的解法一中的常规解决手段,即是位操作。一般是定义一系列的掩码(masks)——可以用宏定义,或者枚举类型——来完成。
参考代码:
说明:
1.看chessTest1,其实只需要printf就可以输出正解,只要AB不同列就可以,共3*3 * 2*3 = 54种情况
2.chessTest2比较不好想,只要注意AB编号不能同时相同(if判断语句中)且AB不同列时才输出就可以
位域的概念《C程序设计语言》用了一页纸介绍,说明了应用场合主要是为了节省空间或直接访问位,应用场景如编译器的符号表以及一些硬件的驱动程序。网络开发、信息编码压缩解压缩、位图等方面可能还会用到,其余的场景多半会去讨论怎么节省时间开销,让程序运行的更加高效。
此外还有一种位读写方式是STL库中提供的泛型类bitset,它支持对位赋值的操作,也支持整体的位运算,最方便的是输入输出流被重载,很容易查看对应的位是否被置正确。相比于位域,bitset不能支持局部几个比特位的访问,而这正是位域的优势。不过对将与帅的问题,要求一个字节,而bitset基本的对齐是4个字节,所以可能不符合题目要求,不过对于其它的位操作场合却是一种很好的选择。
位域的概念《C程序设计语言》用了一页纸介绍,说明了应用场合主要是为了节省空间或直接访问位,应用场景如编译器的符号表以及一些硬件的驱动程序。我想做网络开发、信息编码压缩解压缩、位图等方面可能还会用到,其余的场景多半会去讨论怎么节省时间开销,让程序运行的更加高效。
另解:
要将一个变量i拆成两个,可以根据它的二进制表示分别取出连续几位,比如第0-3位和第4-7位,读变量时,取出变量i相应的几位,存变量时,再更新变量i的对应几位。另外,利用位置的对称性,可以一次输出两个,减少循环次数。
下面的代码和解法一类似,但是一次输出两个,减少了循环次数,并且没有用到除法(不考虑C++ IO效率的影响)
from:http://blog.csdn.net/pipisorry/article/details/36380669
ref:http://www.cnblogs.com/flyinghearts/archive/2010/09/08/1821042.html
问题:下过中国象棋的朋友都知道,双方的“将”和“帅”相隔遥远,并且它们不能照面。在象棋残局中,许多高手能利用这一规则走出精妙的杀招。假设棋盘上只有“将”和“帅”二子(如图1-3所示)(为了下面叙述方便,我们约定用A表示“将”,B表示“帅”):
A、B二子被限制在己方3×3的格子里运动。例如,在如上的表格里,A被正方形{d10, f10, d8, f8}包围,而B被正方形{d3, f3, d1, f1}包围。每一步,A、B分别可以横向或纵向移动一格,但不能沿对角线移动。另外,A不能面对B,也就是说,A和B不能处于同一纵向直线上(比如A在d10的位置,那么B就不能在d1、d2以及d3)。
请写出一个程序,输出A、B所有合法位置。要求在代码中只能使用一个变量。
分析:
题目中仅仅是要求判断将与帅是否照面,而将与帅只能在各自的9个位置移动,因而只需要形式化1~9这9个数字。
此题的解法一中的常规解决手段,即是位操作。一般是定义一系列的掩码(masks)——可以用宏定义,或者枚举类型——来完成。
参考代码:
/****************************************************************************/ /* 1.2中国象棋将帅问题 皮皮 2014-7-1 */ /****************************************************************************/ #include <stdio.h> typedef struct bitField{ unsigned char a:4; unsigned char b:4; }bit; void chessTest1(){ char column = 1; for(; column <=3 ; column ++){ //A的列选 for(; column <= 9; column += 3){ //A(和B)的行选 printf("A = %d, B = %d\n", column, column%3 + 1); printf("A = %d, B = %d\n", column, column%3 + 1 + 3); printf("A = %d, B = %d\n", column, column%3 + 1 + 6); printf("A = %d, B = %d\n", column, (column + 1)%3 + 1); printf("A = %d, B = %d\n", column, (column + 1)%3 + 1 + 3); printf("A = %d, B = %d\n", column, (column + 1)%3 + 1 + 6); } column -= 9; } } void chessTest2(){ char i = 81; while(i--){ if(i/9 % 3 == i % 9 %3) //i/9(A的编号-1[0~8]) % 3(A的列); i%9(B的编号-1[8~0]) %3 continue; //同列则continue printf("A = %d, B = %d\n",i/9 + 1, i%9 + 1); } } void chessTest3(){ bit i; 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) //A B不同列 printf("A = %d, B = %d\n", i.a, i.b); } void main(){<span style="font-family: Arial, Helvetica, sans-serif;"> chessTest3();</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span>
说明:
1.看chessTest1,其实只需要printf就可以输出正解,只要AB不同列就可以,共3*3 * 2*3 = 54种情况
2.chessTest2比较不好想,只要注意AB编号不能同时相同(if判断语句中)且AB不同列时才输出就可以
<span style="font-size:14px;">3.chessTest3使用了位域方法,位域知识参见:http://blog.csdn.net/pipisorry/article/details/36220851</span>
位域的概念《C程序设计语言》用了一页纸介绍,说明了应用场合主要是为了节省空间或直接访问位,应用场景如编译器的符号表以及一些硬件的驱动程序。网络开发、信息编码压缩解压缩、位图等方面可能还会用到,其余的场景多半会去讨论怎么节省时间开销,让程序运行的更加高效。
此外还有一种位读写方式是STL库中提供的泛型类bitset,它支持对位赋值的操作,也支持整体的位运算,最方便的是输入输出流被重载,很容易查看对应的位是否被置正确。相比于位域,bitset不能支持局部几个比特位的访问,而这正是位域的优势。不过对将与帅的问题,要求一个字节,而bitset基本的对齐是4个字节,所以可能不符合题目要求,不过对于其它的位操作场合却是一种很好的选择。
位域的概念《C程序设计语言》用了一页纸介绍,说明了应用场合主要是为了节省空间或直接访问位,应用场景如编译器的符号表以及一些硬件的驱动程序。我想做网络开发、信息编码压缩解压缩、位图等方面可能还会用到,其余的场景多半会去讨论怎么节省时间开销,让程序运行的更加高效。
另解:
要将一个变量i拆成两个,可以根据它的二进制表示分别取出连续几位,比如第0-3位和第4-7位,读变量时,取出变量i相应的几位,存变量时,再更新变量i的对应几位。另外,利用位置的对称性,可以一次输出两个,减少循环次数。
下面的代码和解法一类似,但是一次输出两个,减少了循环次数,并且没有用到除法(不考虑C++ IO效率的影响)
//外层循环变量b使用i的第4-7位,初始值为1,最大值为8。 //内层循环变量a使用i的第0-3位,初始值为b+1,最大值为9。 for (unsigned i = 0x10; i < 0x90; i += 0x10) for (i= (i & 0xF0) | (i >> 4); (++i & 0xF) < 10; ) if (((i & 0xF) - (i >> 4)) != 3 && ((i & 0xF) - (i >> 4)) != 6) std::cout << "A=" << (i >> 4) << ", B="<< (i & 0xF) << "\n" << "A=" << (i & 0xF) << ", B="<< (i >> 4) << "\n";
from:http://blog.csdn.net/pipisorry/article/details/36380669
ref:http://www.cnblogs.com/flyinghearts/archive/2010/09/08/1821042.html
相关文章推荐
- 编程之美读书笔记: 1.2 中国象棋将帅问题
- 编程之美读书笔记_1.2_中国象棋将帅问题
- 编程之美读书笔记1.2——中国象棋将帅问题
- 编程之美 1.2 中国象棋将帅问题
- 《编程之美》:1.2—中国象棋将帅问题
- 1.2中国象棋将帅问题
- 编程之美读书笔记-中国象棋将帅问题
- 编程之美——1.2中国象棋将帅问题
- 编程之美 ---> 1.2中国象棋将帅问题
- 编程之美_1.2中国象棋将帅问题
- 读书笔记之编程之美 - 1.2 中国象棋将帅问题(更快的算法)
- 编程之美 1.2 中国象棋将帅问题
- 编程之美1.2中国象棋将帅问题
- 《编程之美》之读书笔记 1.2中国象棋将帅问题
- 《编程之美》读书笔记01: 1.2中国象棋将帅问题
- 《编程之美》读书笔记01: 1.2中国象棋将帅问题
- 编程之美 1.2 中国象棋将帅问题
- [编程之美] PSet1.2 中国象棋将帅问题
- 编程之美:第一章 1.2 中国象棋将帅问题
- 编程之美1.2中国象棋将帅问题——转载+自己的一点理解