蓝桥杯2017省赛C/C++A组题4方格分割题解(深搜dfs)

标题:方格分割

6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。

如图:
在这里插入图片描述
就是可行的分割法。

试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法

请提交该整数,不要填写任何多余的内容或说明文字。

分析:
经过观察,这种中心对称的分割方法,可以理解为选中心点为横纵第4条边线的交点,中心点为初始起点,从起点沿一个方向走一个格子的边线到一个新的点,两点连成一线,同时再从起点走这条线的中心对称的线,然后再在新到达的起点重复以上过程,直到走到边界,即为完成一次分割。

在这个走的过程中要注意不能走回已经走过的点,故需要标记矩阵记录每个点的访问状况。可以用二维数组保存每个点的访问状态,由于数组下标无法为负数,所以中心点的坐标应为(3,3)。

而且还要注意,对于某一种走法,以过中心点且垂直格子平面的轴为中心轴逆时针旋转90°、180°、270°后本质上仍是同一种走法,这种重复在深搜枚举时无法排除,所以对于最后得出的答案要除以4。

参考代码:

#include<iostream>

using namespace std;

int ans=0;//枚举记数
int vis[7][7] = { 0 };//标记已走过的点
int move[4][2] = { {1,0},//单位移动方向向量
                   {0,1},//从每个点可以往这四个方向走
                   {-1,0},
                   {0,-1} };

void walk(int x, int y)
{
    if (x == 0 || x == 6 || y == 0 || y == 6) {//已到边界,分割完毕
        ans++;
        return;
    }
    vis[x][y] = 1;//先标记
    vis[6 - x][6 - y] = 1;//中心对称的点也标记
    for (int i = 0; i < 4; i++)//走下一个点
    { 
        //四个方向进行枚举,注意不能改变x和y的值,否则会影响到之后的回溯
        if (!vis[ x + ::move[i][0] ][ y + ::move[i][1] ]) {
            walk(x + ::move[i][0], y + ::move[i][1]);
        }
    }
    vis[x][y] = 0;//枚举完毕,清除标记
    vis[6 - x][6 - y] = 0;//对称点的标记也清除
}

int main()
{
    walk(3, 3);//中心点为(3,3)
    cout << ans / 4 << endl;//因为每种走法有3种重复
                            //所以同一种走法会走4次,数4次
    return 0;
}

本题答案为509。

原创文章 34 获赞 87 访问量 2730

猜你喜欢

转载自blog.csdn.net/qq_44643644/article/details/105662302
今日推荐