带剪枝的深搜

what’s 剪枝?

因为深搜都是指数级别的,只要题目数据那么xiao微一大,直接TLE
所以剪枝的重要性就体现出来力。假设你在一棵树上进行深搜,剪枝此时的意思就是字面意思 通过准确且正确的条件进行剪枝,使程序运行时间大大减小

从上到下
时间限制:1秒 内存限制:128M 小可在玩一个格子游戏。格子游戏的地图是一个大正方形,大正方形被分为了 n×n
个小正方形。小可一开始位于左上角的格子,要走到左下角的格子上去。走格子的路径有一个规则,必须路过所有格子恰好一次。如 n=3
时有两种走法:
在这里插入图片描述

现在小可想知道给定 n ,有多少条可行路径
输入描述

一行,一个整数 n

输出描述

一行,一个整数,表示可行路径数

输入样例

3
输出样例

2
数据范围

1<=n<=7

冷静分析:

首先,暴搜看起来异常简单,在一看数据范围似乎确实可以 但细算一下,按上限n=7,此时一共有49个格点,每一个格子有上下左右四种选择——449你猜会不会爆?再多看一眼就会爆炸,毫不犹豫考虑剪枝

剪枝1: 看下面的图 ,走了一圈进了一个死胡同,所以我们的目标就是从死胡同上做文章,but how?
在这里插入图片描述
再看下面的图片,当我们走到中间这个白点时,四周的对点是相反的状态
如果我们往右走,死胡同;往左走,右边的死胡同就进不去了,因为题目规定所有点都得遍历一遍,所以遇到这种情况就剪枝得了

在这里插入图片描述

剪枝2:
在这里插入图片描述

看此图,我们已经走到了点B(然后标记掉),然后点A四周就只有往左的方向没有走过,所以点A只能通过点B走过,所以称点A为点B的必经点
然后如果点B四周出现两个以上的必经点呢?是不是点B只能走其中任意的一个?
那剩下的必经点就变成了三面被标记的死胡同,自然而然就不会产生到达终点的答案
怎么判断一个点是否为必经点?
根据刚才的定义,三面都被标记的点即为必经点,直接计数器++

AC code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<stack>
#include<map>
#define TIE ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define N 15
#define INF 0x3f3f3f3f
using namespace std;
int n, ans, a[N][N];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1};
int getfree(int x, int y) {
	int cnt = 0;
	for (int i = 0; i < 4; i++) {
		if (a[x + dx[i]][y + dy[i]] == 0)
			cnt++;
	}
	return cnt;
}
void dfs(int x, int y, int step) {
	if (x == n && y == 1) {
		if (step == n * n) {
			ans++;
			return;
		}
	}
	if ((a[x][y - 1] && a[x][y + 1] && a[x - 1][y] == 0 && a[x + 1][y] == 0) ||
	        (a[x][y - 1] == 0 && a[x][y + 1] == 0 && a[x - 1][y] && a[x + 1][y]))
		return;
	int cntbijing = 0;
	int nx, ny;
	for (int i = 0; i < 4; i++) {
		int xx = x + dx[i], yy = y + dy[i];
		if (a[xx][yy] || (xx == n && yy == 1)) continue;
		int cnt = getfree(xx, yy);
		if (cnt == 1) {
			cntbijing++;
			nx = xx, ny = yy;
		}
	}
	if (cntbijing > 1)
		return;
	else {
		if (cntbijing == 1) {
			a[nx][ny] = 1;
			dfs(nx, ny, step + 1);
			a[nx][ny] = 0;
		} else {
			for (int i = 0; i < 4; i++) {
				int xx = x + dx[i], yy = y + dy[i];
				if (a[xx][yy] == 0) {
					a[xx][yy] = 1;
					dfs(xx, yy, step + 1);
					a[xx][yy] = 0;
				}
			}
		}
	}
}
int main() {
	TIE;
	cin >> n;
	for (int i = 0; i <= n + 1; i++) {//设置保护区
		a[0][i] = a[n + 1][i] = a[i][0] = a[i][n + 1] = 1;
	}
	a[1][1] = 1;
	dfs(1, 1, 1);
	cout << ans;
	return 0;
}

完结撒花~~~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值