藍橋杯-演算法提高 學霸的迷宮(BFS-倒向追蹤輸出移動方向)

kewlgrl發表於2017-04-06
 演算法提高 學霸的迷宮  
時間限制:1.0s   記憶體限制:256.0MB
    
問題描述
  學霸搶走了大家的作業,班長為了幫同學們找回作業,決定去找學霸決鬥。但學霸為了不要別人打擾,住在一個城堡裡,城堡外面是一個二維的格子迷宮,要進城堡必須得先通過迷宮。因為班長還有妹子要陪,磨刀不誤砍柴功,他為了節約時間,從線人那裡搞到了迷宮的地圖,準備提前計算最短的路線。可是他現在正向妹子解釋這件事情,於是就委託你幫他找一條最短的路線。
輸入格式
  第一行兩個整數n, m,為迷宮的長寬。
  接下來n行,每行m個數,數之間沒有間隔,為0或1中的一個。0表示這個格子可以通過,1表示不可以。假設你現在已經在迷宮座標(1,1)的地方,即左上角,迷宮的出口在(n,m)。每次移動時只能向上下左右4個方向移動到另外一個可以通過的格子裡,每次移動算一步。資料保證(1,1),(n,m)可以通過。
輸出格式
  第一行一個數為需要的最少步數K。
  第二行K個字元,每個字元∈{U,D,L,R},分別表示上下左右。如果有多條長度相同的最短路徑,選擇在此表示方法下字典序最小的一個。
樣例輸入
Input Sample 1:
3 3
001
100
110

Input Sample 2:
3 3
000
000
000
樣例輸出
Output Sample 1:
4
RDRD

Output Sample 2:
4
DDRR
資料規模和約定
  有20%的資料滿足:1<=n,m<=10
  有50%的資料滿足:1<=n,m<=50

  有100%的資料滿足:1<=n,m<=500。




#include<bits/stdc++.h>
using namespace std;
#define MAXN 600
#define INF 0xfffffff
int n,m;
bool ma[MAXN][MAXN],vis[MAXN][MAXN];//存迷宮地圖、標記是否訪問過
int step[MAXN][MAXN],dir[MAXN][MAXN];//步數、當前位置的移動方向
char ans[MAXN];//從起點到終點總的移動方向
int d[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};//移動方向
struct Node
{
    int x,y;//座標
} s,e,pre[MAXN][MAXN];//起終點、當前位置的前一個位置的座標

char shift(int t)//輸出移動方向
{
    if(t==0) return 'U';
    else if(t==1)  return 'D';
    else if(t==2)  return 'L';
    else if(t==3)  return 'R';
}
void path()//從e.x和e.y開始倒推出路徑
{
    int cnt=0;
    ans[cnt++]=shift(dir[e.x][e.y]);//儲存移動方向
    int tx=pre[e.x][e.y].x;//求出當前位置的前一個位置的座標
    int ty=pre[e.x][e.y].y;
    while(1)
    {
        if(tx==0&&ty==0) break;//追尋到了起點之前
        //cout<<dir[tx][ty];
        ans[cnt++]=shift(dir[tx][ty]);//儲存移動方向
        int ax=pre[tx][ty].x;//為了防止tx更新對ty產生影響而先用臨時變數儲存
        int ay=pre[tx][ty].y;
        tx=ax;
        ty=ay;
    }
    for(int i=cnt-2; i>=0; --i)//忽略掉起點
        cout<<ans[i];//倒向追蹤輸出方向
    cout<<endl;
}
bool valid(int x,int y)
{
    if(vis[x][y]==true||ma[x][y]==true||x<=0||x>n||y<=0||y>m) return false;
    return true;
}
void bfs()
{
    queue <Node> q;
    q.push(s);
    vis[s.x][s.y]=true;
    bool flag=false;
    while(!q.empty())
    {
        if(flag) break;
        Node t=q.front();
        q.pop();
        for(int i=0; i<4; ++i)
        {
            Node a;
            a.x=t.x+d[i][0];
            a.y=t.y+d[i][1];
            if(a.x==e.x&&a.y==e.y)//到達終點
            {
                vis[a.x][a.y]=flag=true;
                step[a.x][a.y]=step[t.x][t.y]+1;
                pre[a.x][a.y].x=t.x;
                pre[a.x][a.y].y=t.y;
                dir[a.x][a.y]=i;
                cout<<step[e.x][e.y]<<endl;//輸出步數
                path();
                break;
            }
            if(valid(a.x,a.y))//合法
            {
                vis[a.x][a.y]=true;//標記已經訪問
                step[a.x][a.y]=step[t.x][t.y]+1;//步數更新
                pre[a.x][a.y].x=t.x;//前向座標更新
                pre[a.x][a.y].y=t.y;
                dir[a.x][a.y]=i;//方向更新
                q.push(a);//入隊
            }
        }
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("G:/cbx/read.txt","r",stdin);
    //freopen("G:/cbx/out.txt","w",stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;//行列
    memset(ma,false,sizeof(ma));//初始化
    memset(vis,false,sizeof(vis));
    memset(step,0,sizeof(step));
    memset(dir,-1,sizeof(dir));
    memset(pre,-1,sizeof(Node)*MAXN);
    memset(ans,'\0',sizeof(ans));
    for(int i=1; i<=n; ++i)
    {
        char c[MAXN];//一行行讀入處理
        cin>>c;
        int cnt=0;
        for(int j=1; j<=m; ++j)
            ma[i][j]=c[cnt++]-'0';
    }
    s.x=s.y=1;//起點
    e.x=n,e.y=m;//終點
    bfs();
    return 0;
}


相關文章