中国象棋将帅问题
问题:输出中国象棋将帅所有合法位置,且只能用一个字节存储变量。
分析:此问题的本质是搜索、剪枝,只用一个字节存储变量,意义是要进行位运算,或者用C语言中结构体变量中设定的可以使用结构体变量的低4位或者高四位。
互斥的条件是:不能再同一列即可。
第一步:将问题形式化,给这9个位置编号,这是重要的,类似于表征问题的解空间。
第二步:用位或者结构体变量,或者直接根据数字特征来剪枝解空间。位运算中往往要用到逻辑运算来改变各个位的值。
所以产生下面三种解法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#include "stdafx.h"#include<stdio.h>//宏定义#define HALF_BITS_LENGTH 4 //记忆存储单元的一半#define FULLMASK 255 //全部bit的掩码#define LMASK (FULLMASK<<HALF_BITS_LENGTH) //左bits的掩码#define RMASK (FULLMASK>>HALF_BITS_LENGTH) //右bits的掩码#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 //将帅移动范围的行宽度//解法一void Solve1(){ unsigned char b; 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));}//解法二void Solve2(){ unsigned int i=81; //9*9=81种组合,搜索、剪枝 while(i--) { if(i/9%3==i%9%3) continue; printf("A=%d, B=%d\n",i/9+1,i%9+1); }}//解法三struct{ unsigned char a:4; //a使用结构体变量i的低4位 unsigned char b:4; //b使用结构体变量i的高4位}i;void Solve3(){ 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);}int _tmain(int argc, _TCHAR* argv[]){ printf("------------解法一----------:\n"); Solve1(); printf("------------解法二----------:\n"); Solve2(); printf("------------解法三----------:\n"); Solve3(); return 0;} |
遇到的问题是:
复杂宏定义的括号匹配问题,根据所有问题的解组合,一共有81中解,然后根据不在同一列的数字特征进行剪枝,是一个可取的方法,不过比较难以理解。

浙公网安备 33010602011771号