1. 程式人生 > >[JZOJ 5793] 小S練跑步 {廣搜}

[JZOJ 5793] 小S練跑步 {廣搜}

題目

Description

小S是一個愛鍛鍊的孩子,他在放假期間堅持在A公園練習跑步。但不久後,他就開始為在重複的地點練習感到厭煩了,他就打算去B公園跑步。但是小S由於沒有去過B公園,他不知道B公園是否適合練習跑步,又不知道在B公園怎樣跑是最優的。所以小S就去B公園進行了一番勘測.小S在進行了一番勘測後,畫出了一張地圖,地圖每一個位置上都辨識了小S到達該位置後不能往哪一個方位移動。其中有5種表示的符號:“U”代表不能向上移動,“D”代表不能向下移動,“L”代表不能向左移動,“R”代表不能向右移動,如果該位置有障礙物,小S到達那裡後無法繼續訓練,就用“S”來代表。整個公園共有n行m列,小S會從第1行第1列出發,到第n行第m列結束他的練習。 現在小S想要知道,從起點(即第1行第1列)到終點(第n行第m列),途中最少要改變幾次方向(即上一次移動的方向和這一次移動的方向不一樣)? 注意:小S如在訓練途中離開公園(即地圖範圍),則算是結束訓練。

Input

第1行兩個整數n和m,它們的定義請看【題目描述】。 第2~n+1行,每行有m個字元,表示小S的移動方向。

Output

如果小S從第1行第1列出發無論如何都到達不了第n行第m列,輸出“No Solution”,否則輸出小S途中最少要改變方向的次數。

Sample Input

3 3 ULL LDU SUD

Sample Output

1

[樣例解釋]

小S先向右移動移動了2格,再向下移動2格,就到達了終點,這樣只用改變一次方向。

解題思路

我竟然忘了廣度優先搜尋的效率比我所想的二分答案 +深度優先搜尋要高得多。 我們可以從(1,1)(1,1)開始,標記上下左右僅需移動一次的方格。然後將這些方格放入佇列中,這樣d

isdis佇列得到的移動次數一定是最少的。 要注意的是a[n][m]a[n][m]即使有障礙也能移動到。

_code

#include<cstdio> 
#include<queue>
using namespace std; 
const int xx[4]={0,1,0,-1},yy[4]={1,0,-1,0};
int n,m,b[551][551],a[551][551]; bool g[551][551]; char c; 
queue<int>x,y,dis; 
void bfs()
{
    x.push(1); y.push(
1); dis.push(-1); while (!x.empty()) { int x1=x.front(),y1=y.front(); if (a[x1][y1]!=4){ for (int i=0;i<4;i++) { int k=0; while (1) { k++; int xz=x1+k*xx[i],yz=y1+k*yy[i]; if (xz<1||yz<1||xz>n||yz>m) break; if (a[xz][yz]==4) break; if (a[xz-xx[i]][yz-yy[i]]==i) break; if (g[xz][yz]) continue; g[xz][yz]=1; x.push(xz); y.push(yz); dis.push(dis.front()+1); if (xz==n&&yz==m) { printf("%d",dis.front()+1); return; } } } x.pop(); y.pop(); dis.pop(); } } printf("No Solution"); return; } int main() { scanf("%d%d",&n,&m); c=getchar(); for(int i=1;i<=n;c=getchar(),i++) for(int j=1;j<=m;j++) { c=getchar(); if (c=='R') a[i][j]=0; else if (c=='D') a[i][j]=1; else if (c=='L') a[i][j]=2; else if (c=='U') a[i][j]=3; else if (c=='S') a[i][j]=4; } a[n][m]=-1; bfs(); }