有一个8*8的方格棋盘(如下图所示),现有一匹马从任意一个位置(方格)出发,给出一种方案使马走遍棋盘中的每一个方格,且每个方格只走过一次(马走日字)。

马踏飞燕基本思路

被初始化的全局变量:棋盘、可能马可以走到的点的坐标

自定义函数:nextpos、movenext

主函数功能:

  1. 输入马现在初始的坐标位置
  2. 根据坐标位置去寻找马的出口点
    1. 出口点:在棋盘上,将所有坐标的值设置为0,如果此刻马走过这个点,那么在这个坐标位置下将其值设置为这是第几步走过的这个坐标
    2. 出口点的寻找方式:nextpos方式
      1. 在自定义的nextpos方法中,我们采取了这种方式来寻找出口点:我们将马当前位置的坐标进行输入,然后利用for循环:
        1. 对所有可能走到的点进行边界的判断,如果下一步马走出了棋盘,那么直接结束这步循环,进入到下一步的循环中。
        2. 如果在棋盘中,那么需要对这点的值进行判断,只有这点的值不为0,那么才是没走过的点,否则就是已经走过的点。如果是已经走过的点,那么跳过当前的这步循环。
        3. 如果没有走过,那么就进行count(共有几个出口值点)进行更新(累加),同时更新可以作为出口的点的坐标(利用二维数组)。
      2. 最后对这点的count进行输出
  3. 寻找完当前坐标的所有出口点之后,就需要选择一个出口点进行选择,选择采取的策略是剪枝。方式:movenext
    1. 剪枝的概念是:逐步的去选择可能性最小的坐标点,然后对其进行选择。不断的缩小可能性。
    2. 具体的实施步骤是:
      1. 首先将当前点的坐标点进行带入。
      2. 然后根据我们在nextpos中更新的可能作为pos点的坐标,进行预测:
        1. 预测的概念是:拿着下一步可能走到的点,然后根据这点进行出口点的计算,将预测的结果进行返回。
        2. 具体的实现是依靠for循环,不断的去更新最小出口点数(设置了一个条件:下一步的出口点数不应该大于8,因为最大只有8个出口点(8种走出的路线)),同时更新当前最小点的坐标。直到遍历结束所有的出口点,结束循环。
        3. 通过全局变量记录当前点为找到的下一步中拥有最小出口点的点的x,y方向移动量。同时返回这个点的出口点数。
  4. 通过for循环,同时通过我们设置的全局变量(下一步分别在x,y方向的移动量被我们通过movenext记录),来不断的对下一步点的坐标进行更新。for循环中设置的条件step为累加量,step<64:因为设置的棋盘的大小是8*8大小的,所以最多有64步,我们将step赋给每个下一步,得出了整个棋盘的每个点的被马经过的顺序。
  5. 将棋盘每个点的值输出,为我们找到的路径。
  6. 程序结束。
#include <cstdio>
#include <cstdlib>
int move1[8]={2,2,1,1,-1,-1,-2,-2,},
        move2[8]={1,-1,2,-2,2,-2,1,-1,},
        board[8][8]={{0}};
int nexti[8],nextj[8],npos,cur_row,cur_col,step,outwrite=1;

/*函数nextpos计算位置(i,j)出口个数*/
int nextpos(int i,int j,int a[8],int b[8])
{
    int count=0,k,i1,j1;
    for(k=0;k<8;k++){
        i1=i+move1[k];
        j1=j+move2[k];
        if(i1>7||i1<0||j1>7||j1<0)
            continue;
        else if(board[i1][j1]!=0)
            continue;
        else{
            a[count]=move1[k];
            b[count]=move2[k];
            ++count;
            printf("i is %d\n",a[count]);
            printf("j is %d\n",b[count]);
        }
    }

    return(count);
}

/*函数movenext在有多出口时,选择适当出口推进一步*/
int movenext(int *i,int *j,int a[],int b[])
{
    int temp,count=8,a1[8],b1[8],
            nexti_like[8],nextj_like[8],
            cur_row_like,cur_col_like,k,t;

    for(k=0;k<npos;k++)
    {
        temp=nextpos(*i+nexti[k],*j+nextj[k],a1,b1);
        if(temp<count)
        {
            cur_row_like=*i+nexti[k];
            cur_col_like=*j+nextj[k];
            count=temp;
            for(t=0;t<count;t++)
            {
                nexti_like[t]=a1[t];
                nextj_like[t]=b1[t];
            }
        }
    }
    *i=cur_row_like;
    *j=cur_col_like;
    for(k=0;k<count;k++)
    {
        a[k]=nexti_like[k];
        b[k]=nextj_like[k];
    }
    return count;
}


int main()
{
    int i,j;
    printf("\nEnter the starting position(row,col):");
    scanf("%d",&cur_row);/*输入起始位置*/
    scanf("%d",&cur_col);
    board[cur_row][cur_col]=1;
    npos=nextpos(cur_row,cur_col,nexti,nextj);
    printf("nexti is %d",nexti[0]);
    printf("出口数量为 %d",npos);
    for(step=2;step<=64;step++)
    {
        if(npos==0){
            outwrite=0;
            break;
        }
        else if(npos==1){
            cur_row+=nexti[0];
            cur_col+=nextj[0];
            board[cur_row][cur_col]=step;
            npos=nextpos(cur_row,cur_col,nexti,nextj);
        }
        else{
            npos=movenext(&cur_row,&cur_col,nexti,nextj);
            board[cur_row][cur_col]=step;
        }
    }
    if(outwrite==0)
        printf("\n no solution\n");
    else{
        printf("\n A solution:\n");
        for(i=0;i<8;i++){
            for(j=0;j<8;j++)
                printf("%4d",board[i][j]);
            printf("\n");
        }
    }
    printf("%d",board[5][6]);
    system("pause");
}

输出的是为马走过的点的顺序。
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 对于一个 n×m 的棋盘,其包含的正方形数量为: 1×1 的正方形数量为 (n×m) 个; 2×2 的正方形数量为 (n-1)×(m-1) 个; 3×3 的正方形数量为 (n-2)×(m-2) 个; ... k×k 的正方形数量为 (n-k+1)×(m-k+1) 个。 因此,n×m 的棋盘包含的正方形数量为: (n×m) + ((n-1)×(m-1)) + ((n-2)×(m-2)) + ... + (1×1) 对于长方形,我们可以枚举其左上角和右下角的位置,即共有 (n-1)×(m-1) 种可能性。因此,n×m 的棋盘包含的长方形数量为: (n-1)×(m-1) 注意,这里不包括正方形。 ### 回答2: 正方形: 对于 n×m 的棋盘,其最短边长为 1,最长边长为 min(n,m),所以包含的正方形个数为: 1² + 2² + 3² + ... + min(n,m)² 可以用数学公式简化上述求和式: 1² + 2² + 3² + ... + n² = n(n+1)(2n+1)/6 所以包含的正方形个数为: min(n,m)(min(n,m)+1)(2min(n,m)+1)/6 长方形: 首先考虑宽和高都不相同的长方形。对于宽为 i,高为 j 的长方形,其可以从棋盘任意 i 个竖行和任意 j 个横行组成,所以包含的长方形个数为: (n-i+1) × (m-j+1) 将宽和高交换,结果一样,所以计算出所有宽高不同的长方形个数,再减去正方形的个数,就是所有长方形的个数。 接下来考虑宽和高相同的长方形,其宽高可以为 1,2,3,...,min(n,m)。对于宽高为 i 的正方形,其可以从棋盘任意 i 个竖行和任意 i 个横行组成,所以包含的长方形个数为: (n-i+1) × (m-i+1) 将所有同宽高不同的长方形数加起来,再加上同宽高的正方形数,就是所有长方形的个数。 综上所述,棋盘包含的长方形个数为: 所有宽高不同的长方形个数 - 所有正方形个数 + 所有宽高相同的长方形个数 = ∑[(n-i+1) × (m-j+1)] - ∑[min(n,m)²] + ∑[(n-i+1) × (m-i+1)] ### 回答3: 对于一个n x m的棋盘,我们可以将其分解为一个个小正方形。在这些小正方形,我们可以找到不同形状的正方形和长方形。 先考虑正方形的数量。对于一个n x m的棋盘,我们可以在里面找到不同大小的正方形。例如:当n=1或m=1时,无法构成任何大小的正方形;当n=2或m=2时,只能构成1个2x2的正方形;当n=m=3时,可以构成4个1x1的正方形、1个2x2的正方形和1个3x3的正方形;当n=m=4时,可以构成9个1x1的正方形、4个2x2的正方形和1个3x3的正方形;以此类推。 由此可得,n x m的棋盘,正方形的数量为: 1² + 2² + 3² + … + min(n, m)² 这是因为当n > m时,最大的正方形边长为m,所以计算到m;当n <= m时,最大的正方形边长为n,所以计算到n。 接下来考虑长方形的数量。我们可以从n x m的棋盘选择两行和两列,构成一个长方形。由于有n行和m列,因此可以选择的行有n*(n-1)/2种,选择的列有m*(m-1)/2种。所以总共可以构成的长方形数量为: n*(n-1)/2 * m*(m-1)/2 但我们要排除掉正方形的情况。正方形可以由两行和两列组成,所以排除掉的数量为: 1² + 2² + 3² + … + min(n, m)² 因此,n x m的棋盘,长方形的数量为: n*(n-1)/2 * m*(m-1)/2 - (1² + 2² + 3² + … + min(n, m)²) 综上所述,n x m的棋盘,正方形的数量为1² + 2² + 3² + … + min(n, m)²,长方形的数量为n*(n-1)/2 * m*(m-1)/2 - (1² + 2² + 3² + … + min(n, m)²)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

胖羊驼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值