非常好的一道搜索题,花了一个下午和一个晚上去做去理解
题意:虽然英语很长,不过不是太难懂,就是可以向四个方向扔小球,每次扔出去,会一直走,直到遇到墙时停止,或出界失败,而遇到墙后,球会停止,然后所撞到的墙消失,给一个起点和一个终点,能在10步之内到达的则输出其最少步数
思路:虽然是搜dfs题目搜到的这道题,但是开始看题意是说要求最少的步数,第一个想到的自然是BFS,感觉稍微变形下,类似回溯,只是每次都是四个方向同时判断,然后入队,再继续广搜。然而,花了整整2个多小时,依然调不好,思路也越来越乱了,上百度搜了下,全是dfs的解法。仔细看了下,发现和自己写的bfs几乎一致,于是,决定从新再写一遍,改一改回溯,希望能更短时间内完成,而且图不大,空间换时间还是值得的。当然,更主要的原因是,不知道没理解为什么最少步数却没人用bfs呢……
但当我正真再次改的时候,突然发现了问题所在,因为bfs是同时想各个方向的,而每次如果撞到一面墙A,而另一方向搜的时候,这个被撞的墙A还是存在的,所以要做bfs理论上也是可以的,只是每次向外搜索一次,每个方向都应该增加一个20*20的数组,这个空间是否开的起真是一个问题……而且即使开的起,也是极不划算的,因为题目只要在10次之内,所以dfs也不会浪费太多时间
以下是代码,改自网上一个代码(ps:他的代码当时还开了一个宽搜用的结构体数组,没有删掉,呵呵,看来不止我一个人遇到这个问题)
code:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 25;
int sqr[N][N], w , h;
int dir[4][2] = {{1 , 0} , {-1 , 0} , {0 , -1} , {0 , 1}};
int ret ;
void DFS(int a , int b , int step)
{
if(step > 10 || step > ret) return;
for(int i=0; i < 4; i++)
{
int at = a + dir[i][0];
int bt = b + dir[i][1];
if(at <= 0 || bt <= 0 || at > h || bt > w)
continue;
if(sqr[at][bt] == 1) continue;
int flag = 0;
int tx = a , ty = b;
while(sqr[at][bt] != 1)
{
tx = at, ty = bt;
if(sqr[at][bt] == 3 && step + 1 <= 10)
{
ret = min(ret , step + 1);
}
at += dir[i][0];
bt += + dir[i][1];
if(at <= 0 || bt <= 0 || at > h || bt > w)
{
flag = 1;
break;
}
}
if(flag) continue;
sqr[at][bt] = 0;
DFS(tx , ty , step + 1);
sqr[at][bt] = 1;
}
}
int main()
{
//freopen("in.txt" , "r" , stdin);
while(scanf("%d %d" , &w , &h), w && h)
{
int sx ,sy;
ret = 20;
for(int i=1; i <= h; i++)
for(int j=1; j <= w; j++)
{
scanf("%d" , &sqr[i][j]);
if(sqr[i][j] == 2)
{
sx = i;
sy = j;
}
}
DFS(sx , sy , 0);
printf("%d\n" , ret == 20 ? -1 : ret);
}
return 0;
}