最少步数 (递归 搜寻)

本文探讨如何利用递归算法来寻找问题的最少步数解决方案,详细解析递归搜索的过程及其在解决复杂问题中的应用。

最少步数

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
描述

这有一个迷宫,有0~8行和0~8列:

 1,1,1,1,1,1,1,1,1
 1,0,0,1,0,0,1,0,1
 1,0,0,1,1,0,0,0,1
 1,0,1,0,1,1,0,1,1
 1,0,0,0,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,1,0,0,1
 1,1,0,1,0,0,0,0,1
 1,1,1,1,1,1,1,1,1

0表示道路,1表示墙。

现在输入一个道路的坐标作为起点,再如输入一个道路的坐标作为终点,问最少走几步才能从起点到达终点?

(注:一步是指从一坐标点走到其上下左右相邻坐标点,如:从(3,1)到(4,1)。)

输入
第一行输入一个整数n(0<n<=100),表示有n组测试数据;
随后n行,每行有四个整数a,b,c,d(0<=a,b,c,d<=8)分别表示起点的行、列,终点的行、列。
输出
输出最少走几步。
样例输入
2
3 1  5 7
3 1  6 7
样例输出
12

11



这道题其实并不难,没有想象的那么复杂繁琐,你要做的只是从一个点向4个方向搜寻而已。每个步骤方法相似,我们自然就想到了递归


能递归求解的问题要满足以下三个条件

(1)能将一个问题转变成一个新问题,且新问题与原问题的解法相同,不同之处是处理的对象,并且这些处理对象更小且变化更有规律

(2)可以通过上诉转化而使问题更简化

(3)必须有一个明确的递归出口

这三个条件是不是觉得我讲的很理论,因为这是我课本原话。微笑


在调用递归过程中,永远不要尝试用你的脑容量来跟踪每一个递归的脚步,简单的问题还好(例如无脑递归求幂),一稍微复杂,很难一步步跟着递归脚步(例如汉诺塔问题,递归树等),我一开始也想明确跟踪每一个递归的脚步,但是一层接着一层,我的脑子有点不够用。所以你只需要明白递归的方向,只要你思路是对的,结果肯定是你期望的。


以下是代码实现(注释我已经很详细的说明了,无脑儿也能看懂):

#include<iostream>
using namespace std;
			
int map[9][9]={						 //初始化地图,用二维数组表示平面地图
1,1,1,1,1,1,1,1,1,					 //0是道路 1是墙
 1,0,0,1,0,0,1,0,1,  
 1,0,0,1,1,0,0,0,1,  
 1,0,1,0,1,1,0,1,1,  
 1,0,0,0,0,1,0,0,1,  
 1,1,0,1,0,1,0,0,1,  
 1,1,0,1,0,1,0,0,1,  
 1,1,0,1,0,0,0,0,1,  
 1,1,1,1,1,1,1,1,1  
};
int walk_x[4]={1,0,-1,0};				//+dx[i],+dy[i]就可以表示向某个方向走一步,共4个方向
int walk_y[4]={0,1,0,-1};   

int x,y,xx,yy,fx,fy;				//(x,y)表示起点,(fx,fy)表示终点,(xx,yy)表示过程位置
int sum,c;							//sum表示最少步数,c表示临时总步数的记录	 (先初始化最少步数为999)

void find_way(int x,int y,int c){    
	if(x==fx&&y==fy){				//如果到达终点
		if(c<sum)					//取最少的步数
			sum=c;   
	}
	else{                           //如果还没到终点
		for(int i=0;i<4;i++)
		{
			int xx=x+walk_x[i];         //走一步
			int yy=y+walk_y[i];
		
			if(map[xx][yy]==0&&c+1<sum)     //如果下一步可以走(不会撞墙),且临时步数记录是小于当前最少步数的(要是大于等于最少步数,就不用继续走了,没意义)
			{
				map[xx][yy]=1;              //标记走过的点,这样就不会往回走(让走过的位置标记为墙)
				find_way(xx,yy,c+1);		//运用递归的思想,继续探寻终点
				map[xx][yy]=0;				//这一层递归结束后,返回原来上一次位置,要把刚刚标记为墙的变回原来的道路
			}
		}
	}
}

int main(){
	int n;
	cin>>n;
	while(n--)
	{
		cin>>x>>y>>fx>>fy;
		map[x][y]=1;						//把起点设置为"走过"的状态(不能回头,且从出发点出发的)
		sum=999;							//先初始化最少步数为999
		c=0;								//初始化临时步数记录为0
		find_way(x,y,c);					//调用函数
		cout<<sum<<endl;
		map[x][y]=0;						//结束时要把起点"还原"(刚把起点表示为墙了),以便可以下一组数据的测试
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值