2022.03.25蓝桥杯第八届 4.方格分割(dfs)

  • 题目描述
    6x6的方格,沿着格子的边线剪开成两部分。
    要求这两部分的形状完全相同。
    如图:p1.png, p2.png, p3.png 就是可行的分割法
    请添加图片描述

  • 试计算:
    包括这3种分法在内,一共有多少种不同的分割方法。
    注意:旋转对称的属于同一种分割法。
    请提交该整数,不要填写任何多余的内容或说明文字。

  • 我的想法(因为之前写过一遍所以有点印象)
    从最中间的那个点(3,3)开始dfs,按照两种相反的走法走,当走到边界时,这两条路线合在一起将方格分割成两部分

#include <iostream>
#include<string.h>
using namespace std;
int cnt;
bool vis[7][7];
int dir1[4][2]={-1,0,1,0,0,-1,0,1};
int dir2[4][2]={1,0,-1,0,0,1,0,-1};//第二条路的走法和第一条相反
bool check(int a,int b,int c,int d){//确保两个点都到了边界
    int flag1=0,flag2=0;
    if(a==0||a==6||b==0||b==6) flag1=1;
    if(c==0||c==6||d==0||d==6) flag2=1;
    if((a+c==6)&&(b+d==6)&&flag1&&flag2) return true;
    else return false;
}
void dfs(int a,int b,int c,int d){
    if(check(a,b,c,d)){
        cnt++;
        return;
    }
    for(int i=0;i<4;++i){
        int da=a+dir1[i][0];
        int db=b+dir1[i][1];
        int dc=c+dir2[i][0];
        int dd=d+dir2[i][1];
        if(da<0||da>6||db<0||db>6||dc<0||dc>6||dd<0||dd>6||vis[da][db]||vis[dc][dd]){
            continue;
        }
        vis[da][db]=true;vis[dc][dd]=true;
        dfs(da,db,dc,dd);
        vis[da][db]=false;vis[dc][dd]=false;
    }
}
int main()
{
    cnt=0;
    memset(vis,false,sizeof(vis));
    vis[3][3]=true;
    dfs(3,3,3,3);
    cout<<cnt/4<<endl;
    return 0;
}

  • 还有更简洁的写法
    可以发现第二条路线是与第一条路线相反的方向走的,那达到的点其实与第一条线到达的点是关于(3,3)对称的,比如点(3,2)和(3,4)可以发现它们的横纵坐标和为6,那dfs就可以不需要4个参数了,两个就好,即只需要知道一条路的走法就好了,且当一条路走到了边界,那另一条路也必定到了边界,因为它们的对称关系
#include<iostream>
using namespace std;

int vis[10][10] = {0};
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

int ans = 0;

void DFS(int x,int y)
{
	if(!x || !y || x==6 || y==6)//判断到边界了
	{
		ans++;
		return ;
	}
	for(int i = 0; i < 4; i++)
	{
		int tempx = x + dir[i][0];
		int tempy = y + dir[i][1];
		if(!vis[tempx][tempy])//这里不用判断超没超边界,必不可能超
		//假设超了边界那tempx,tempy应该是由边界点走出来的,也就是x,y是边界点
		//但是如果x,y是边界点,在上面的if中就return掉了,所以不可能
		{
			vis[tempx][tempy] = 1;
			vis[6-tempx][6 - tempy] = 1;//对称点
			DFS(tempx,tempy);
			//这里为什么要复原?可以看下面的图
			vis[tempx][tempy] = 0;
			vis[6-tempx][6 - tempy] = 0;
		}
	}
}
int main()
{
	vis[3][3] = 1;
	DFS(3,3);
	cout << ans/4 <<endl;//为什么除以4?
	//因为ans把所有走法都算了,但是题目说了旋转对称的属于同一种分割法
	//而一种走法按旋转不同来算就有四种走法
	return 0;
} 

黑点可以通过绿线的走法走到,也可以通过蓝线的走法走到,假设先按绿线走,那走完后黑点的vis为真,然后进一步dfs下一步走法
但是在dfs完绿线方案后必须将黑点的vis置为false,因为蓝线的走法也有可能得到答案,它也要能走黑点
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值