蓝桥杯:方格分割 特别的dfs思路 以及一些dfs的总结

题目描述

6x6的方格,沿着格子的边线剪开成两部分。要求这两部分的形状完全相同。
如图就是三种合法的分割:
在这里插入图片描述
试计算:包括这3种分法在内,一共有多少种不同的分割方法。注意:旋转对称的属于同一种分割法。

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

思路

这题一开始我是想暴力列举18个点,然后判断,发现时间复杂度太高

然后我又想对格子dfs,发现dfs无法做到那种有分叉的,弯曲的形状,遂放弃

后来想了想:我用剪刀剪,一刀肯定可以完成,而且剪的痕迹要对称,剪到边界,我就完工了啊

恍然大悟:

这题dfs的不是格子,而是dfs剪刀剪切的痕迹

因为一刀可以切完,代表没有分叉的路,剪切的痕迹对称,就是dfs的约束条件,剪切到边界完工,这是dfs的边界条件啊

既然不是对格子dfs,每次我们又只能剪切在格子的边上,那么将方格抽象成剪刀可以经过的点,那么这个点阵的大小是 7x7
在这里插入图片描述

如图:剪切的痕迹关于中心点对称
在这里插入图片描述

因为剪切的痕迹关于点阵的中心对称

  • 我们从点阵的中心出发,向任意方向上的,剪刀未经过的点移动,直到到达点阵的边界

到达边界,说明已经全部被切开了,那么我们找到了一种可能的答案

注意:最后的答案要除4,因为一张正方形的纸,用相同的剪切手法,从四个边入手,得到的形状会是一样的,而我们剪切的时候没有考虑到这个,故会出现中心对称的情况(同一种手法,可以出现4次)

代码

#include <iostream>

using namespace std;

int p[7][7] = {0};
int ans = 0;

bool can(int x, int y)
{
	if(0<=x && x<7 && 0<=y && y<7)
	 	if(p[x][y]==0) return true;
	return false;
}

void dfs(int x, int y)
{
	if(x==0 || x==6 || y==0 || y==6){ans++; return;}
	p[x][y]=p[6-x][6-y]=1;
	if(can(x-1, y)) dfs(x-1, y);
	if(can(x+1, y)) dfs(x+1, y);
	if(can(x, y-1)) dfs(x, y-1);
	if(can(x, y+1)) dfs(x, y+1);
	p[x][y]=p[6-x][6-y]=0;
}

int main()
{
	dfs(3, 3);
	cout<<ans/4<<endl;
	
	return 0;
}

总结

dfs适合的情况是一条路走到黑,即

  • 路径没有分叉

面对一道题目,考虑使用dfs的条件就是:我的答案会有分叉的情况吗?

如果答案中包含有分叉的情况,比如上面分叉的格子也是合法的切割,那么就不能使用dfs,应该在状态没有分叉的问题上使用dfs

因为dfs代表一种“走法”,在dfs 的时候,也要注意,我们的图是否是对称的,得出的答案是否会出现对称的情况,如果对称出现了,那么应该如何去重,都是要考虑的

发布了171 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104576120