深搜&&广搜_Poj_3083

//题目大意是一直靠着左边墙往前走,记下找到终点的步数
//再一直靠着右边墙往前走,记下找到终点的步数
//然后用广搜搜出到达终点所需的最短的步数
//PS:<1>到达某一点时要记录到达时所面对的方向 
//         <2>到达某一点后,要弄清搜索4个方向的顺序搜索的方向是和所靠的墙的方向是相反的

//       比如靠着左墙走,那么一点搜索到左边是墙,就有往该(面对墙)方向往右前进


//PS2:绝对到苦力题啊! T.T  做的我泪流满面

//PS3 :加强了搜索题中对顶点各个方向的处理能力


#include<iostream>
#include<queue>
using namespace std;

//定义往左深搜的搜索顺序数组,0,1,2,3分别代表右上左下
int go_left_x[4]={0,-1,0,1};
int go_left_y[4]={1,0,-1,0};

//定义往右深搜的搜索顺序数组,0,1,2,3分别代表右下左上
int go_right_x[4]={0,1,0,-1};
int go_right_y[4]={1,0,-1,0};

//定义到达终点所用的步数
int left_sum,right_sum,least_sum;

/*------以下为两种搜索共用的变量--------*/

//定义输入图的个数
int n;

//存储地图
char g[41][41];

//存储图的纵数和横数
int g_y,g_x;

//定义开始点和结束点的坐标
int start_x,start_y,end_x,end_y;

//看是否在图内
bool IsIn(int now_x,int now_y)
{
if(now_x<0||now_x>=g_x||now_y<0||now_y>=g_y) return false;
else return true;
}

//左深搜,direction代表进入该点时所面对的方向,num代表走到该点所用的步数
void dfs_left(int now_x,int now_y,int direction,int num)
{
if(now_x==end_x && now_y==end_y)
left_sum=num;
else
{
//定义到当前方向的左边并开始四个方向顺序遍历,选且只选其中一个方向
direction=(direction+1)%4;//将右上左下四个方向分别标记0,1,2,3,所以往左转就是(当前方向+1)%4
//开始遍历,如果当前方向不成功就往右转,就是(当前方向+1)%4
int next_x,next_y;
int i;
for(i=0;i<4;i++)
{
next_x=now_x+go_left_x[direction];
next_y=now_y+go_left_y[direction];
//如果当前前进方向的各自在图内且可走,则前进且终断当前循环,因为每一步只选一种方向
if(IsIn(next_x,next_y) && g[next_x][next_y]!='#')
{
dfs_left(next_x,next_y,direction,num+1);
break;
}
//不成功,右转
else direction=(direction+3)%4;
}
}
}

//复制上面的稍加修改:右深搜,direction代表进入该点时所面对的方向,num代表走到该点所用的步数
void dfs_right(int now_x,int now_y,int direction,int num)
{
if(now_x==end_x && now_y==end_y)
right_sum=num;
else
{
//定义到当前方向的左边并开始四个方向顺序遍历,选且只选其中一个方向
direction=(direction+1)%4;//将右下左上四个方向分别标记0,1,2,3,所以往左转就是(当前方向+1)%4
//开始遍历,如果当前方向不成功就往右转(即保证靠着墙前进),就是(当前方向+3)%4
int next_x,next_y;
int i;
for(i=0;i<4;i++)
{
next_x=now_x+go_right_x[direction];
next_y=now_y+go_right_y[direction];
//如果当前前进方向的各自在图内且可走,则前进且终断当前循环,因为每一步只选一种方向
if(IsIn(next_x,next_y) && g[next_x][next_y]!='#')
{
dfs_right(next_x,next_y,direction,num+1);
break;
}
//不成功,左转
else direction=(direction+3)%4;
}
}
}

//接下来定义广搜所要用到的
bool sign[40][40];

struct Node
{
int x,y,num;
}node[41][41];

//定义队列
queue<Node>Q;

void bfs()
{
int now_x, now_y,now_num;
now_x=Q.front().x;
now_y=Q.front().y;
now_num=Q.front().num;
//遍历四个方向可达的点并入栈
int tx,ty;
int i;
for(i=0;i<4;i++)
{
//用go_left_x和go_right_x都一样,目的只是访问四个方向顶点,顺序如何无妨
tx=now_x+go_left_x[i];
ty=now_y+go_left_y[i];
if(IsIn(tx,ty) && !sign[tx][ty] && g[tx][ty]!='#')//在图上且未访问过的点同时不是墙的,入队列
{
//标记node[tx][ty]已经访问过
sign[tx][ty]=true;


node[tx][ty].x=tx;
node[tx][ty].y=ty;
node[tx][ty].num=now_num+1;

Q.push(node[tx][ty]);
}
}
Q.pop();
while(!Q.empty())
{
now_x=Q.front().x;
now_y=Q.front().y;
now_num=Q.front().num;
//如果已经是终点则返回,终止搜索
if(now_x==end_x && now_y==end_y)
{
least_sum=now_num;
return;
}
for(i=0;i<4;i++)
{
tx=now_x+go_left_x[i];
ty=now_y+go_left_y[i];
if(IsIn(tx,ty) && !sign[tx][ty] && g[tx][ty]!='#')//在图上且未访问过的点同时不是墙的,入队列
{
sign[tx][ty]=true;


node[tx][ty].x=tx;
node[tx][ty].y=ty;
node[tx][ty].num=now_num+1;
Q.push(node[tx][ty]);
}
}
Q.pop();
}
}

int main()
{
while(cin>>n)
{
while(n--)
{
cin>>g_y>>g_x;//先输入列才输入行
int i,j;
for(i=0;i<g_x;i++)
scanf("%s",g[i]);
//记录下开始顶点和结束顶点
for(i=0;i<g_x;i++)
{
for(j=0;j<g_y;j++)
{
if(g[i][j]=='S')
{
start_x = i;
start_y = j;
}
if(g[i][j]=='E')
{
end_x = i;
end_y = j;
}
}
}
//确定开始时面对的方向
int direction;
if(start_x==g_x-1) direction=1;//开始时方向朝上
else if(start_x-1 == 0) direction=3;//方向朝下
else if(start_y == 0) direction=0;//方向朝右
else direction=2;//方向朝左
//往左深搜
dfs_left(start_x,start_y,direction,1);
printf("%d ",left_sum);
//往右深搜(方向数字不同,重新确定方向数字)
if(start_x==g_x-1) direction=3;//开始时方向朝上
else if(start_x-1 == 0) direction=1;//方向朝下
else if(start_y == 0) direction=0;//方向朝右
else direction=2;//方向朝左
dfs_right(start_x,start_y,direction,1);
printf("%d ",right_sum);
//广搜
memset(sign,0,sizeof(sign));
while(!Q.empty())
Q.pop();
node[start_x][start_y].x=start_x;
node[start_x][start_y].y=start_y;
node[start_x][start_y].num=1;
sign[start_x][start_y] = true;
Q.push(node[start_x][start_y]);
bfs();
printf("%d\n",least_sum);
}
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值