DFS暴搜无法解决的问题——剪枝操作

一个正方形的镇区分为 N*N(1≤N≤7) 个小方块。农场位于方格的左上角,集市位于左下角。

Betsy 穿过小镇,从左上角走到左下角,刚好经过每个方格一次。

当 N=3时,Betsy 的漫游路径可能如下图所示:

| | | |

| F********** |

| | | * |

------------*—

| | | * |

| ***** | * |

| * | * | * |

----*—

| * | * | * |

| M | ****** |

| | | |

请你帮忙计算 Betsy 有多少种不同的旅行方案。

Input

输入一行一个整数 N(1 \le N \le 7)

Output

输出一行表示不同的路径数。

Sample Input Copy

3

Sample Output Copy

2

这题一看就是DFS的经典问题要遍历所有的路线,尝试一波暴力搜索

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=105;
int v[maxn][maxn];
int dr[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,ans=0;
void dfs(int x,int y,int step)
{	int tx,ty; 
	if(x==n&&y==1&&step==n*n)
	{
	ans++;
	return ;
	}
	for(int i=0;i<4;i++)
	{
		 tx=x+dr[i][0];
		 ty=y+dr[i][1];
		if(tx>0&&tx<=n&ty>0&&ty<=n&&!v[tx][ty])
		{
			v[tx][ty]=1;
			dfs(tx,ty,step+1);
			v[tx][ty]=0;
		 } 
	}
}
int main()
{
	cin>>n;
	v[1][1]=1;
	dfs(1,1,1);
	printf("%d",ans);
	return 0;
}

但数据范围过大,会在6的时候就被卡住

此时就要想到如何舍弃一些必不可能的解,把这些解快速的筛掉;

1.第一种能想到的剪枝手段就是不能提前就到达终点去

if(x == n && y == 1)//剪枝1,不能提前到达终点
	{
		if(sum==n*n) ans++;
		return;
	}

2.第二个剪枝手段是你所在目前地的上下方向和左右方向如果其中一组走过而另外一组未走过这时候可以直接剪枝筛掉,因为已经无法遍历了;

if((map[x][y-1] && map[x][y+1] && !map[x-1][y] && !map[x+1][y]) || 
	   (!map[x][y-1] && !map[x][y+1] && map[x-1][y] && map[x+1][y])) //剪枝2,孤立区域剪枝
		return;

2.第三种剪枝手段就比较难想一些就是要对目前地的周围的必经地进行判断如果多于一个直接剪掉
只有一个的话就直接走那个必经之地,没有的话就对周围的地区都遍历一次

int get(int x, int y)
{
	int t=0;
	for(int k=0;k<4;k++)
		if(!map[x+pos[k][0]][y+pos[k][1]])
			t++;
	return t;
}
//未经之地的个数
```	for(int i=0;i<4;i++)//剪枝3,格子的度的处理	
	{
		int X=x+pos[i][0],Y=y+pos[i][1];
		if(map[X][Y] || (X==n && Y==1)) continue;
		if(get(X,Y)<2)
		{
			count++;
			mx=X;
			my=Y;	
		}
	}
	
	if(count>1)
		return;
	else
		{
			if(count==1)
			{
				map[mx][my]=1;
				dfs(mx,my,sum+1);
				map[mx][my]=0;
			}
			else
				for(int i=0;i<4;i++)
				{
					int X=x+pos[i][0], Y=y+pos[i][1];
					if(!map[X][Y])
					{
						map[X][Y]=1;
						dfs(X,Y ,sum+1);
						map[X][Y]=0;
					}
				}
		}
}
完整代码便是这样的
#include<iostream>
#include<cstdio> 
using namespace std;
 
bool map[9][9];
int pos[][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int n,ans=0;
 
int get(int x, int y)
{
	int t=0;
	for(int k=0;k<4;k++)
		if(!map[x+pos[k][0]][y+pos[k][1]])
			t++;
	return t;
}
 
void dfs(int x, int y, int sum)
{
	if(x == n && y == 1)//剪枝1,不能提前到达终点
	{
		if(sum==n*n) ans++;
		return;
	}
	if((map[x][y-1] && map[x][y+1] && !map[x-1][y] && !map[x+1][y]) || 
	   (!map[x][y-1] && !map[x][y+1] && map[x-1][y] && map[x+1][y])) //剪枝2,孤立区域剪枝
		return;
	int mx,my,count=0;
	for(int i=0;i<4;i++)//剪枝3,格子的度的处理	
	{
		int X=x+pos[i][0],Y=y+pos[i][1];
		if(map[X][Y] || (X==n && Y==1)) continue;
		if(get(X,Y)<2)
		{
			count++;
			mx=X;
			my=Y;	
		}
	}
	
	if(count>1)
		return;
	else
		{
			if(count==1)
			{
				map[mx][my]=1;
				dfs(mx,my,sum+1);
				map[mx][my]=0;
			}
			else
				for(int i=0;i<4;i++)
				{
					int X=x+pos[i][0], Y=y+pos[i][1];
					if(!map[X][Y])
					{
						map[X][Y]=1;
						dfs(X,Y ,sum+1);
						map[X][Y]=0;
					}
				}
		}
}
 
int main(){
	cin >> n;
	for(int i=1;i<=n;i++)	//处理边界
		map[1][1]=map[0][i]=map[n+1][i]=map[i][0]=map[i][n + 1]=1;
	dfs(1,1,1);	
	cout<<ans<< endl;
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ctgu20-acm-律

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

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

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

打赏作者

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

抵扣说明:

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

余额充值