《编程之美》学而思-中国象棋将帅问题

探讨了中国象棋中将帅的所有合法位置的计算方法,提供了两种使用位操作和数学运算实现的高效算法,并详细解释了算法背后的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中国象棋将帅问题

flyfish 2015-8-11

问题引自 《编程之美》中国象棋将帅问题
将帅每一着只许走一步,前进、后退、横走都可以,但不能走出“九宫”,被限制在3×3的格子里运动。将和帅不准在同一直线上直接对面。
请写出一个程序,输出将帅所有合法的位置,要求在代码中只能使用一个变量.
约定用a表示“将”,b表示“帅”

一个解法是关于位操作 跳过

原文提供解法一

struct {
    unsigned char a:4;
    unsigned char b:4;
} i;

    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);

思路是将一个变量拆成两部分

原文提供解法二

BYTE i = 81;
while (i--)
{
    if (i / 9 % 3 == i % 9 % 3)
        continue;
    printf ("A = %d, B = %d\n", i / 9 + 1, i % 9 + 1);
}

问题转换
有个两位数m,十位上的数是a,个位上是b
每个位上的数只能是从1到9组成,则共有9*9=81种组成方式

a[1,9]={a|1a9}
b[1,9]={b|1b9}

两位数数列
11、12、13、14、15、16、17、18、19
21、22、23、24、25、26、27、28、29

当下标从0开始时,各个数就减1, 就完全成了一个9进制的数,满9进1
10、11、12、13、14、15、16、17、18
20、21、22、23、24、25、26、27、28

10进制的81 ,9进制也就是100
9进制表示
这里写图片描述

十位数= m / 9
个位数= m % 9

将帅只有3列可移动,将帅不能位于同一列也就是共有9*(9-3)=54种组成方式

a%3 != b%3

因为下标从0开始时,各个数已经减1,输出时需要加1
m / 9 + 1
m % 9 + 1

关于循环
1 两位数最大99 所以循环可以从99开始递减
2 每个位上的数只能是从1到9组成有81种方式,则可以从81开始递减
3 合法的位置有54种,所以可以从54开始递减
4 当前a和b的位置符合条件的话,那么将a,b位置对调之后的位置也符合条件,则可以将循环从27开始

循环从54开始,以三进制输出
这里写图片描述

        BYTE i=54;
        while (i--)
        {
            printf("A = %d%d,",i/18,i%18/6);
            printf("B = %d%d\n",i%3,(( (i%6/3+i%18/6) %3 +1)%3));
        }

这里写图片描述
图中3进制 由两位组成,别表示行和列

像这样A的一个位置,对应B的6个位置
A的1列有3个位置,每个位置可对应B的6个位置,共3*6=18个位置

0行 A[0,17]
1行 A[18,35]
2行 A[36,53]

A的行 i/18
A的列 i%18/6

B的行 i%3
B的列 ((i%6/3+i%18/6) %3 +1)%3

如果循环从27开始时,需要在while 循环中再加两行printf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二分掌柜的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值