最少转弯问题
时间限制: 1 Sec 内存限制: 128 MB
题目描述
给出一张地图,这张地图被分为n×m(n,m<=100)个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的(x1,y1)这块平地,问:你至少需要拐几个弯才能到达目的地(x2,y2)?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。例如:如图,最少的拐弯次数为5。
输入
第1行:n m
第2至n+1行:整个地图地形描述(0:空地;1:高山),
如(图)第2行地形描述为:1 0 0 0 0 1 0
第3行地形描述为:0 0 1 0 1 0 0
……
第n+2行:x1 y1 x2 y2 (分别为起点、终点坐标)
输出
输出s (即最少的拐弯次数)
样例输入
5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 0 1 0 1
0 1 1 0 0 0 0
0 0 0 0 1 1 0
1 3 1 7
样例输出
5
思路:
em.....之前做的时候是练习广搜时的专题,也没有怎么想,直接套广搜模版就直接AC了。ε=(´ο`*)))
感谢@qq_43399909 这位大佬提供的测试数据。我又重新理解了一下题意,发现之前代码错误的地方是判断转折点的方式是错误的,判断转折点的思路后面写,废话不多说了,先看代码
代码如下
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
struct node{
int x,y,step;//当前的坐标,转弯次数
} beg,ed,p;//beg-起点;ed-终点
queue<node> q;
int n,m,maps[110][110];//地图
int dir[][2]={0,1,1,0,0,-1,-1,0};//四个方向
bool used[110][110];//标记:是否走过
int main()
{
memset(used,0,sizeof(used));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&maps[i][j]);
scanf("%d%d%d%d",&beg.x,&beg.y,&ed.x,&ed.y);
q.push(beg);
q.front().step=0;
//bfs
while(!q.empty())
{
for(int i=0;i<4;i++)
{
p.x=q.front().x+dir[i][0];
p.y=q.front().y+dir[i][1];
//从当前位置出发往某方向一直走,直到遇到边界或高山则停止,再从本位置换下一个方向走
while(p.x>0&&p.x<=n&&p.y>0&&p.y<=m&&!maps[p.x][p.y])
{
if(!used[p.x][p.y])//没有走过时
{
if(p.x==ed.x&&p.y==ed.y)
{
printf("%d\n",q.front().step);//注意输出的是当前队头的转弯次数。
return 0;
}
used[p.x][p.y]=1; // 走过后标记
p.step=q.front().step+1;//统计转弯次数
q.push(p);
}
//沿着一个方向一直走,在之前的位置上,继续按原来的方向走
p.x=p.x+dir[i][0];
p.y=p.y+dir[i][1];
}
}
q.pop();
}
}
qq_43399909 这位大佬提供 的测试样例
8 8
0 0 1 1 0 0 0 0
1 0 0 0 0 1 1 0
1 1 0 0 1 1 1 0
1 1 1 0 0 1 1 0
1 1 1 1 0 0 1 0
1 1 1 1 1 0 1 0
1 1 1 1 1 0 1 0
1 1 1 1 1 0 0 0
1 1 8 8
转折点的判断:
求最少的拐弯次数
=》 最好是沿着一个方向直接走到终点
=》 所以在原有广搜的基础上,修改一下:
每走完一步不要急着换队列节点,沿着某一方向走下去,直到不能走为止,然后再换,直到走到终点。
然后我根据大佬提供的样例,用表格模拟了一下了,
表格中的数字表示当前位置得出的最短拐弯次数
红色的格子表示1:高山
黄色的格子表示0 : 空地
蓝色的格子表示: 从起点到终点最短转弯次数路径
起点:白色
终点:绿色