阅读编程之美:微软技术面试心得总结
~中国象棋将帅问题
‘将’和‘帅’都各自在自己的‘大本营’移动,在程序中输出所有两个棋子不在一条线上落子方法,只能使用一个变量。
~算法分析
抛开只使用一个变量的要求,这其实是一个很简单的问题,用0到8九个数字代表落子的位置,遍历每一个数字,对3进行求余,如果余数不相等,就代表没在一条直线上。
如果没有只使用一个变量的要求的确很简单,代码如下:
int jiangTemp;
int shuaiTemp;
for(jiangTemp = 0; jiangTemp < 9; jiangTemp++)
{
for(shuaiTemp = 0; shuaiTemp < 9; shuaiTemp++)
{
if(shuaiTemp%3 != jiangTemp%3)
{
cout<<"没有在一条直线上"<<endl;
}
}
}
很简单的程序,但是如果只是用一个变量的话,就得用一个变量代表两个数字,数字范围不需要很大,能容纳下9个数字就行,bool值只能代表两个数字,因此不可用,int值范围又太大,因此我们折中选择byte,byte是一个8位的类型,可以表示256个数字,我们用前4位代表将棋,用后四位代表帅棋。
第一步:对右边四位赋值
这里我们只做一次循环的分析,假设byte b当前的值为:
10100101
我们先清除掉右边4位的值,获得左边四位的值:
11110000&10100101
上边运算得出结果:
10100000
然后让结果和n(需要给右边四位复制的数字)^运算:
10100000^00000011
得出结果:
10100011
这样就完成了对右边四位的赋值
第二步:对左边四位赋值
我们先清除掉左边4位的值,获得左边四位的值:
00001111&10100011
得出结果:
00000011
将需要赋值的数字n向左移动四位:
n<<4 = 00110000
byte b和n的值进行^运算:
00110000^00000011
得出结果:
00110011
第三步:左右两个值进行运算
清除左边4位:
00110011&00001111
得出结果:
00000011
清除右边4位:
00110011&11110000
得出结果:
00110000
将结果向又有移动4位:
00110000>>4 = 00000011
得到的两个结果分别%3结果不相等则输出没在一条直线上。
代码如下:
#include <stdio.h>
#define HALF_BITS_LEN 4
#define FULL_MASK 255
#define LMASK (FULL_MASK << HALF_BITS_LEN)
#define RMASK (FULL_MASK >> HALF_BITS_LEN)
#define RSET(b, n) (b = (LMASK & b) ^ n)
#define LSET(b, n) (b = (RMASK & b) ^ (n << HALF_BITS_LEN))
#define RGET(b) (RMASK & b)
#define LGET(B) ((LMASK & B) >> HALF_BITS_LEN)
#define GRIDW 3
int main()
{
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));
}
}
}
}