1.2 中国象棋将帅问题进一步讨论与扩展:如何用1个变量实现N重循环?[chinese chess]

【题目】

假设在中国象棋中只剩下将帅两个棋子,国人都知道基本规则:将帅不能出九宫格,只能上下左右移动,不能斜向移动,同时将帅不能照面。问在这样条件下,所有可能将帅位置。要求在代码中只能使用一个字节存储变量

【分析】

3种方案:

1)位运算实现1个byte存入和读取2个变量。

2)使用位域把几个不同的对象用一个字节的二进制位域来表示。比如

C++ Code


1
2
3
4
5
 
struct
{
    unsigned char a: 4;
    unsigned char b: 4;
} i;

3)使用1个变量表达2重循环。后面将会重点讨论该方案。(思考:如何用1个变量实现N重循环?)

【位运算】

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/24
*/
#include<stdio.h>
#define HALF_BITS_LENGTH 4
#define FULLMASK 255
#define LMASK (FULLMASK << HALF_BITS_LENGTH)
#define RMASK (FULLMASK >> HALF_BITS_LENGTH)
#define RSET(b,n) (b = (b & LMASK) | (n))
#define LSET(b,n) (b = ((b & RMASK) | ((n) << HALF_BITS_LENGTH)))
#define RGET(b) (b & RMASK)
#define LGET(b) ((b & LMASK)>>HALF_BITS_LENGTH)
#define GRIDW 3

void Solution1()
{
    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));
            }
        }
    }
}

位域

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/24
*/
struct
{
    unsigned char a: 4;
    unsigned char b: 4;
} i;

void Solution2()
{
    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) // column not equal
                printf("%d,%d\n", i.a, i.b);
}

【单个变量】

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/24
*/
void Solution3()
{
    unsigned char i = 81;
    while(i--)
    {
        // i = 9*a+b, a = i/9, b = i%9
        if (i / 9 % 3 == i % 9 % 3)
            continue;
        printf("%d,%d\n", i / 9, i % 9);
    }
}

“将”和“帅”各在自己的3*3的格子间里面走动,我们共需要验证9*9=81种位置关系,这也是i=81的由来。此外我们要明白 i/9和i%9的含义。我们知道,整数i可以由部两分组成,即i=(i/9)*9+i%9 。我们注意到,在i从81到0变化的过程中,i%9的变化相当于内层循环,i/9的变化相对于外层循环。

【扩展】

如何用1个变量实现N重循环?

先看个简单例子,1个变量实现2重循环。

C++ Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/24
*/
void LoopWith2Variables()
{
    unsigned char i, j;
    for(i = 0; i < 5; i++)
        for(j = 0; j < 4; j++)
            printf("%d,%d", i, j);
}

void LoopWith1Variable()
{
    unsigned char val = 4 * 5;
    while(val--)
    {
        printf("%d,%d", (val / 4) % 5, val % 4);
    }
}

【总结】

对于 a*b = i ,我们可以用如下公式展开:

loop1=i%b;

loop2=(i/b)%a

其中loop1是内层循环,loop2是外层循环。

由此可以得出N重时的公式,假设 an * a(n-1) * ....... * a3 * a2 * a1 = N

loop1=N%a1

loop2=(N/(a1))%a2

loop3=(N/(a1a2))%a3

.....

loopN=(N/(a1a2.....a(n-1)))%an

【参考】

http://blog.csdn.net/kabini/article/details/2256421

http://blog.csdn.net/silenceburn/article/details/6133222

http://blog.csdn.net/zhongkeli/article/details/8779168

http://www.cnblogs.com/python27/archive/2012/04/10/2441114.html

【本文链接】

http://www.cnblogs.com/hellogiser/p/chinese-chess.html

1.2 中国象棋将帅问题进一步讨论与扩展:如何用1个变量实现N重循环?[chinese chess]

时间: 2024-07-30 12:04:48

1.2 中国象棋将帅问题进一步讨论与扩展:如何用1个变量实现N重循环?[chinese chess]的相关文章

编程之美读书笔记1.2——中国象棋将帅问题

http://blog.csdn.net/pipisorry/article/details/36380669 问题:下过中国象棋的朋友都知道,双方的"将"和"帅"相隔遥远,并且它们不能照面.在象棋残局中,许多高手能利用这一规则走出精妙的杀招.假设棋盘上只有"将"和"帅"二子(如图1-3所示)(为了下面叙述方便,我们约定用A表示"将",B表示"帅"): A.B二子被限制在己方3×3的格子

编程之美笔记--第一章游戏之乐--1.2中国象棋将帅问题

后来一版作者又将最后一句改为:”要求在代码中只能使用一个字节存储变量“. 我的解法: package android.zlb.java; /** * * @author zhanglibin * */ public class TestXiangqi { public static void main(String[] args) { for(int i = 11; i < 100; i++) { if(i / 10 % 3 == 1 && (i % 10 == 1 || i % 1

《编程之美》读书笔记:中国象棋将帅问题

找出将和帅所有可能的局面,要求用一个字节的变量来存储数据. 我最初分析这道题,想可以枚举将的位置,那么一共有9个,再写出帅的位置就行,由于将帅不能照面,所以此时帅只有6个位置.答案必定有9*6=54个.只是判断照面的地方会比较麻烦. 由于只有一个字节的变量限制和以前做题经验,使我一度想歪以为要用二进制的位来表示将的位置.但是这样的话,一个字节只有8位,而将可有9个位置,显然不行. 当然,不应这样做,也没有必要这样. 后来想到另一种思路,可以把将和帅的位置同时压缩到一个十进制数字N里面,这样N=a

《编程之美》之中国象棋将帅问题

一个将,一个帅,在各自的活动的9个格子里,但是两个人不能面对面,站在同一条直线上 下面两种简单的解法 #include <stdio.h> int main() { unsigned char i = 81; while (i--) { if (i / 9 % 3 == i % 9 % 3) continue; printf("a:%d,b:%d\n", i / 9, i % 9); } struct { unsigned char a:4; unsigned char b

《编程之美-读书笔记》-1 中国象棋将帅问题

时间:2014.05.27 地点:基地 ---------------------------------------------------------------------------------------- 一.指针和引用的区别 1.指针可以为空,引用不可以不空. 引用是一个对象的别用,定义一个引用时必须初始化,而声名指针时可以不指向任何对象,故使用指针时也常要做空的判断,而引用无需,因为引用总是绑定着一个对象. 2.指针可以改变指向,而引用不可以重新绑定新对象.(指针变异思迁,引用从

中国象棋将帅问题

中国象棋将帅问题 flyfish 2015-8-11 问题引自 <编程之美>中国象棋将帅问题 将帅每一着只许走一步,前进.后退.横走都可以,但不能走出"九宫",被限制在3×3的格子里运动.将和帅不准在同一直线上直接对面. 请写出一个程序,输出将帅所有合法的位置,要求在代码中只能使用一个变量. 约定用a表示"将",b表示"帅" 一个解法是关于位操作 跳过 原文提供解法一 struct { unsigned char a:4; unsig

第1章 游戏之乐——中国象棋将帅问题

中国象棋将帅问题 中国象棋里面双方的“将”和“帅”各自呆在自己的九宫格里,一步只能横移或纵移一格,而且双方不能见面(既不能处在同一条纵线上).在残局时有的人会用这一规则走出绝妙杀招.假设一方的“将”为A,另一方的“帅”为B,现在求双方所能出现的所有合法位置,所需变量只能用一个字节来保存. 我们用1~9的数字来,按行优先的顺序来表示每个格点的位置,如下图所示.这样只需要用模余运算就可以得到当前的列号,从而判断A.B是否互斥. [解法一]用C语言实现 一种比较正经的解法,就是用位运算,设一个char

1.2中国象棋将帅问题

(根据中国象棋的基本原则)在只有双的将帅棋盘上,找出所有双方可以落子的位置(将帅不能碰面),但只能使用一个变量. 直觉上我们想到,只要遍历将帅所有可能的位置,去除将帅冲突的位置即可.可见,剩下的问题就在于如何使用一个变量来做二重循环的遍历.书中解法一给出的方法是将一个Byte变量拆成两个用,前一半代表"帅"可以走的位置,后一个变量代表"将"可以走的位置(事先已经将"将"和"帅"可以走的3*3的位置进行了编号),利用位操作即可获

《编程之美》中国象棋将帅问题

问题描述 中国象棋里面双方的"将"和"帅"各自呆在自己的九宫格里,一步只能横移或纵移一格,而且双方不能见面(既不能处在同一条纵线上).在残局时有的人会用这一规则走出绝妙杀招.假设一方的"将"为A,另一方的"帅"为B,现在求双方所能出现的所有合法位置,所需变量只能用一个字节来保存. 我的解法 #include <stdio.h> int main(void) { unsigned char chPos = 0x11;