面试题:中国象棋将帅问题

xiaoxiao2021-02-28  78

中国象棋将帅问题(输出所有将帅的合法位置) 我们看一下怎么来看将和帅的位置,来比较她们两的位置是否会冲突 我们用数字1~9来标记棋子的位置然后进行比较A=将,B=帅 本题的难点其实是在 如何使用一个变量来保存这一个将,还有另一个帅的位置 第一种方法 那我们其实可以这样,我们可以使用一个8个比特的变量来保存这两个数据,前四个比特来保存A的位置,后四个比特来保存B的位置 四个比特刚好可以保存2^4=16个数字而我们的将和帅的位置刚好是有9个数字构成的所有我们用16个数字来保存绰绰有余 那么我们怎么用这一个8比特的变量分别用他的前后四比特来 分别保存两个值,然后又怎么将这两个值有分别从这一个变量中 取出来进行比较呢? 首先是将这两个将与帅的位置保存起来(b为前一次运算后的结果) 先保存B=1 首先清除结果右边的字节,为后面将B的位置保存做准备    0000 0000   (b) &1111 0000   (LMASK)    ( &运算有0即0
   0000 0000   (b&LMASK) 再将得到的这个数字和我们即将要保存的B相或,就将B的位置保存下来了    0000 0000      (b&LMASK) |  0000 0001      (B)          ( |运算有1即1
   0000 0001      (b) 得到结果 00000001 再保存A=1 首先清除上一步结果中左边字节,为保存A的位置做准备    0000 0001        (b) &0000 1111        (RMASK)
   0000 0001        (RMASK&b) 再将A的位置保存进去 将A的位置保存之前我们先要将A<<4 0000 0001<<4=0001 0000  (A<<4) 再将A变化后的结果与我们运算后的b|起来  0001 0000    (A<<4) |0000 0001    (b)
 0001 0001     (b) 得到结果0001 0001,即位置A=1,B=1 总的来说 将这两个位置保存起来的话只需要一句话 (((b&LMASK)|B)&RMASK)|(A<<4) 再将这两个将与帅的位置取出进行比较(b为上一步保存后的结果,将这个结果保存起来,之后会用到) 先得到B的位置    0001 0001       (b) &0000 1111       (RMASK)
   0000 0001       (B的位置) 再得到A的位置    0001 0001         (b) &1111 0000         (LMASK)
   0001 0000           再将这个结果>>4即 0001 0000>>4=0000 0001 (A的位置) 在得到又取出A、B位置之后我们在进行位置的比较,之后输出符合条件的位置(符合条件的位置即AB的位置不能处于同一条直线上, 即将这个值%3若相同则在同一行) 然后我们来写代码 #define _CRT_SECURE_NO_WARNINGS 1 #define BITS 4 #define FULLNUMBER 255 #define LMASK ( FULLNUMBER << BITS )     //1111 0000 #define RMASK ( FULLNUMBER >> BITS )     //0000 1111 #define RSET (b,n)  (b=((b& LMASK )^n))        //将b的右边设置成n #define LSET (b,n)  (b=((b& RMASK )^(n<< BITS ))) //将b的左边设置成n #define RGET (b)    (b& RMASK )                 //得到b右边的值 #define LGET (b)    ((b& LMASK )>> BITS )          //得到b右边的值 #include<stdio.h> int main() {       unsigned char b = 0;       for ( LSET (b, 1); LGET (b) <= 9; LSET (b, ( LGET (b) + 1)))      {             for ( RSET (b, 1); RGET (b) <= 9; RSET (b, ( RGET (b) + 1)))            {                  if ( RGET (b) % 3 != LGET (b) % 3)                 {                      printf( "A=%d,B=%d\t\t" , LGET (b), RGET (b));                 }            }      }            system("pause");       return 0; } 结果呢是这样的 第二种方法 因为将与帅问题的位置共有9*9=81种结果,我们就要在这81种结果中找出符合条件的位置打印出来 那么我们拥有的这个变量只要可以保存81个这么多的变量就可以了 那我们还是用unsigned char型变量有8字节,最大可以保存255种情况 (书上用的是BYTE,BYTE在VC中就表示的是unsigned char,但是在VS中没有这个变量类型) 先看代码 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> int main() {       unsigned char i = 81;       while (i--)      {             if (i / 9 % 3 == i % 9 % 3)            {                  continue ;            }            printf( "A=%d,B=%d\t\t" , i / 9 + 1, i % 9 + 1);      }      system( "pause" );       return 0; } 其实这个方法呢就是利用数学的方法,例如73-81 i/9就一直是8,i%9即1-8,就刚好是将与帅所对应的位置 再%3运算之后进行比较,将符合条件的打印 这个方法真的特别巧妙,理解理解重在理解 第三种方法 第三种方法是在第一种方法上做的改进,也使用位运算,但是我们使用了一个位段的结构,刚好是按byte来保存数据 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct {       unsigned char a : 4;       unsigned char b : 4; }i; //位段名字 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)            {                 printf( "A=%d,B=%d\t\t" , i.a, i.b);            }      }      system( "pause" );       return 0; } 这个方法是直接利用位段,直接按位来保存数据,按位来读取数据,然后再进行比较,符合条件的直接打印,这个方法其实也比较简单 综上所述,其实第二种方法最简单,但是及其不容易想到,第三种其实也比较简单,不过要是对位段不熟悉的话也写不出来,第一种呢是最容易想到的,但是操作起来及其麻烦,而且稍有不慎就会做错,这得需要对位运算十分了解才可以,并且 在使用宏的时候一定要小心运算符的优先级,如果对这个不大清楚的话那么你就直接加括号,括号千万不要少,要记住括号是优先级的死敌
转载请注明原文地址: https://www.6miu.com/read-2613804.html

最新回复(0)