zoukankan      html  css  js  c++  java
  • 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 ", 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 ", 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 ", 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

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    C#委托本质探索 四、方法变量内、外混合调用
    calibredrv 对layer做操作
    2021年11月工作笔记
    2022年1月工作资料
    2021年12月工作资料
    MySQL 5.7 MGR原理及部署
    在虚拟机上安装redis集群,redis使用版本为4.0.5,本机通过命令客户端可以连接访问,外部主机一直访问不了
    mongoDB中的的常用语法
    使用Nginx做图片服务器时候,配置之后图片访问一直是 404问题解决
    jquery.cookie() 方法的使用(读取、写入、删除)
  • 原文地址:https://www.cnblogs.com/hellogiser/p/chinese-chess.html
Copyright © 2011-2022 走看看