問題描述
給出一張地圖,這張地圖被分為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)。