浅析搜索(search)NO.3

  废话不多说上题目

 

【题目部分】

有一个mn格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可走,文件读入这mn个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的的行号和列号)。现在要你编程找出所有可行的道路总数,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用 -1表示无路)。

Input

 

第一行是两个数 m、n(1 < m,n < 15),接下来是m行n列由10组成的数据,最后两行是起始点和结束点。

Output

 

所有可行的路径总数。如果没有一条可行的路则输出 -1.

Sample Input 1

5 6

1 0 0 1 0 1

1 1 1 1 1 1

0 0 1 1 1 0

1 1 1 1 1 0

1 1 1 0 1 1

1 1

5 6

Sample Output 1

12

第一次看到这个题目,我的内心是:这什么东西讲的啥,一点都听不懂,直接不做了

但是让我讲个东西你和我可能就明白了:

迷宫类的搜索,需要一些处理技巧。

对于迷宫类的搜索,假设当前点为 i ,j ,按照本题迷宫的走法,它可以向上下左右四个方向走动:

1、迷宫边界问题

因为在走的过程中,可能会走出迷宫边界,所以每走一步都需要判断是否是边界,比如向上走,可能会超出上边界,向下走可能会超出下边界等等。常规的办法就是判断走到的点的坐标是否在迷宫内部,但是比较繁琐。

一种处理的技巧就是对给定的迷宫四周加个围墙,对于本题,所谓围墙就是把迷宫的四周都赋值为0,相当于把迷宫外围一圈都设置为不可走

这样在程序处理时的好处:不用考虑边界问题(因为边界的位置是0,走不了),程序就会简洁多了。

迷宫边界?处理?判断?

bool m[20][20];

用0或false在m数组中表示边界或不能走的地方,既然要加一个围墙,那么读入的时候就要注意一个小细节:

for(int i=1;i<= m;i++) //迷宫从第一行开始存放 

  for(int j=1;j<= n;j++) //迷宫从第一列开始存放 

    cin>>m[i][j]; 

为什么i,j都是从1开始呢?因为有个围墙啊( ⊙ o ⊙ )!

自己理解吧qwq

2、四个方向的处理

常规的做法是四个方向分别处理

比如:void mg(int x,int y){........}

向上走:mg(x-1,y);

向右走:mg(x,y+1);

.....

这样需要调用四次,一种巧妙的做法是设置增量数组,原理是对当前点来说:

如果向上走,行 -1 ,行增量就是 -1;列 不变,列增量就是 0;

如果向左走,行 不变,行增量就是 0 ;列 -1 ,列增量就是-1;

如果向下走,行 +1 ,行增量就是 +1;列 不变,列增量就是 0;

如果向右走,行 不变,行增量就是 0 ;列 +1 ,列增量就是+1;

然后用一个数组存行的增量,另一个数组存列的增量,比如下面的写法:

int dx[]={-1,0,1,0};//上左下右四个方向的行增量

int dy[]={0,-1,0,1};//上左下右四个方向的列增量

比如:void mg(int x,int y){........}

四个方向的走动就可以用循环处理:

for(int i=0;i<4;i++)

mg(x+dx[i],y+dy[i]);

这样看完是不是就有一个代码的基础框架在我们的脑海里浮现了呢?反正我当时没感觉

我们先处理边界问题,之后运用回溯算法(推个文章NO.1NO.2)对要走的方向进行试探(递归?),直到碰到死胡同(0或false),返回(return),对另一个方向进行试探...

 

上代码:

#include<bits/stdc++.h>
using namespace std;
bool ma[25][25];//ma即map用来标记走过的路
int bk[4]={0,0,1,-1},dy[4]={-1,1,0,0};//增量数组
int n,m,ax,ay,bx,by,w[25][25],ans=0;//w即walk用来储存迷宫图案
//ax,ay是起点的坐标,bx,by是终点坐标
bool bj;//负责查看有没有至少一条路径
void dfs(int a,int b){
	if(a==bx&&b==by){//如果到达终点
		bj=1;//标记
		ans++;//方案++
		return ;//返回
	}
	for(int i=0;i<4;i++){
		if(ma[a+bk[i]][b+dy[i]]==0&&w[a+bk[i]][b+dy[i]]==1){
                        //判断是否走过并且要走的方向没有障碍物(墙?)
			ma[a][b]=1;//标记
			dfs(a+bk[i],b+dy[i]);//继续试探
			ma[a][b]=0;//回溯一步
		}
	}
	return ;//结束
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>w[i][j];
	cin>>ax>>ay>>bx>>by;
	dfs(ax,ay);
	if(bj){
		cout<<ans;
	}
	else{
		cout<<-1;
	}
	return 0;
}

byebye~~ <( ̄3 ̄)>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值