编程之美(二)中国象棋将帅问题

版权声明:本文为博主原创文章,转载请注明出处-- https://blog.csdn.net/qq_38790716/article/details/90272026

如下图
在这里插入图片描述

将 被限制于{ d 10 , f 10 , d 8 , f 8 d_{10}, f_{10}, d_8, f_8 }组成的正方形中,帅 被限制于{ d 3 , f 3 , d 1 , f 1 d_3, f_3, d_1, f_1 }组成的正方形中,要求将和帅不能照面,给出将和帅的所有合法位置;如果没有特别的要求,那么应该用一个双重循环即可搞定,但题目中给出限制:只能使用一个字节存储变量

解法一 (位运算)

一个字节也即 8 b i t 8bit ,而我们需要保存将和帅两个点的位置信息,对于将/帅 4 b i t 4bit 大小存储足够描述其 9 9 种位置,所以可以将 8 b i t 8bit 分为左右两边,左边 4 b i t 4bit 存储将的位置,右边 4 b i t 4bit 存储帅的位置,通过位运算不断更新左值与右值的大小,达到双重循环遍历的效果

#include <iostream>
#include <time.h>
using namespace std;
#define HALF_BITS_LENGTH 4  //4bits
#define FULLMASK 255   //一个完整bits,为11111111
#define LMASK (FULLMASK << HALF_BITS_LENGTH)   //表示左bits,为11110000
#define RMASK (FULLMASK >> HALF_BITS_LENGTH)   //表示右bits,为00001111
#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  //表示将帅移动范围的行宽度
int main() {
    unsigned char b;
    clock_t start, finish;
    start = clock();
    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) {
                cout << "A = " << LGET(b) << ",B = " << RGET(b) << endl;
            }
        }
    }
    finish = clock();
    cout << endl << "runTime: " << (double)(finish - start) / CLOCKS_PER_SEC << "s" << endl;
    return 0;
}

测试结果:
在这里插入图片描述

解法二 (/、%)

利用 / / 、%进行遍历, ( n 1 ) k (n - 1) * k ~ n k / k n * k / k 可以得到 k 1 k - 1 ,而利用%则可以得到 0 0 ~ k 1 k - 1 ,这样就达到了遍历的作用

#include <iostream>
#include <time.h>
using namespace std;
int main() { 
    unsigned char i = 81;
    clock_t start, finish;
    start = clock();
    while (i--) {
        if (i / 9 % 3 == i % 9 % 3)
            continue;
        cout << "A = " << i / 9 + 1 << ",B = " << i % 9 + 1 << endl;
    }
    finish = clock();
    cout << "runTime: " << (double)(finish - start) / CLOCKS_PER_SEC << "s" << endl;
    return 0;
}

测试结果:
在这里插入图片描述

解法三 (结构体、位域)

利用位域性质,限定变量存储地址,例:unsigned char a : 4,表示只用其中的低4位,然后双重循环遍历

#include <iostream>
#include <time.h>
using namespace std;
struct {
    unsigned char a : 4;
    unsigned char b : 4;
} i;
int main() { 
    clock_t start, finish;
    start = clock();
    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)
                cout << "A = " << (int)i.a << ",B = " << (int)i.b << endl;
        }
    }
    finish = clock();
    cout << "runTime: " << (double)(finish - start) / CLOCKS_PER_SEC << "s" << endl;
    return 0;
}

测试结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38790716/article/details/90272026
今日推荐