最少步数
-
描述
-
这有一个迷宫,有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,10表示道路,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; }
- 第一行输入一个整数n(0<n<=100),表示有n组测试数据;