中国象棋将帅问题

问题:输出中国象棋将帅所有合法位置,且只能用一个字节存储变量。

分析:此问题的本质是搜索、剪枝,只用一个字节存储变量,意义是要进行位运算,或者用C语言中结构体变量中设定的可以使用结构体变量的低4位或者高四位。

互斥的条件是:不能再同一列即可。

第一步:将问题形式化,给这9个位置编号,这是重要的,类似于表征问题的解空间。

第二步:用位或者结构体变量,或者直接根据数字特征来剪枝解空间。位运算中往往要用到逻辑运算来改变各个位的值。

所以产生下面三种解法:

#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中解,然后根据不在同一列的数字特征进行剪枝,是一个可取的方法,不过比较难以理解。

 

posted @ 2013-07-04 10:21  李VS超  阅读(660)  评论(0编辑  收藏  举报