问题描述
给出一张地图,这张地图被分为n×m(n,m<=100)个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的(x1,y1)这块平地,问:你至少需要拐几个弯才能到达目的地(x2,y2)?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。例如:如图,最少的拐弯次数为5。
输入
第一行:n和m。
第二至n+1行:一个矩阵,为地图。(0:空地;1:高山。)
第n+2行:x1,y1,x2和y2。
输出
只有一行,为最少的转弯次数。
Sample input
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
Sample output
5
算法分析:
参考:
http://blog.csdn.net/qq_30720681/article/details/50865093
http://blog.csdn.net/imaxtime/article/details/53038473
广搜,从出发点开始广搜。出发点入队,然后开始循环广搜。
每一次取出队头元素,从队头元素沿着四个方向中的一个方向直线前进直到行不通再换下一个方向。(注意,换方向后,队头尚未出队,还是从原先的队头出发,从下一个方向直线前进。)
每一轮直线前进过程中遇到的那些点的转弯次数都是当前队头元素的转弯次数(假如遇到了目的地,那就输出当前队头元素的转弯次数。)但是假如没有遇到目的地,当前遍历的点存储的转弯次数应该是“扫描到该点的队头的转弯次数再加1”。
说这么多,不如直接看代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 6 const int dx[]={0,1,0,-1};//右下左上 7 const int dy[]={1,0,-1,0}; 8 struct point 9 { 10 int x,y,turn; 11 }_begin,_end,p; 12 queue<point> q; 13 int n,m,_map[101][101]; 14 bool used[101][101]; 15 16 int main() 17 { 18 memset(used,0,sizeof(used)); 19 20 scanf("%d%d",&n,&m); 21 for(int i=1;i<=n;i++) 22 for(int j=1;j<=m;j++) 23 scanf("%d",&_map[i][j]); 24 scanf("%d%d%d%d",&_begin.x,&_begin.y,&_end.x,&_end.y); 25 26 q.push(_begin); 27 q.front().turn=0; 28 while(!q.empty()) 29 { 30 for(int i=0;i<4;i++) 31 { 32 p.x=q.front().x+dx[i]; 33 p.y=q.front().y+dy[i]; 34 //从队头出发往dx[i]和dy[i]方向一直走,直到遇到边界或高山则停止,再从原队头换下一个方向走 35 while(p.x>0&&p.x<=n&&p.y>0&&p.y<=m&&!_map[p.x][p.y]) 36 { 37 if(!used[p.x][p.y]) 38 { 39 if(p.x==_end.x&&p.y==_end.y) 40 { 41 printf("%d\n",q.front().turn);//注意输出的是当前队头的转弯次数。 42 return 0; 43 } 44 used[p.x][p.y]=1; 45 p.turn=q.front().turn+1; 46 q.push(p); 47 } 48 p.x+=dx[i]; 49 p.y+=dy[i]; 50 } 51 } 52 q.pop();//当前队头元素已经不能再扩展,可以删除队头 53 } 54 }
假如还没明白,自行跟踪一下吧,下面是一个案例:
输入:
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
上面红色部分是路线。
可以换一个更简单的案例,比如把上面案例的目的点坐标改为(1,5)以及(3,4)。