洛谷p2802 回家(dfs回溯)

題目描述
小H在一個劃分成了n*m個方格的長方形封鎖線上。 每次他能向上下左右四個方向移動一格(當然小H不可以靜止不動), 但不能離開封鎖線,否則就被打死了。 剛開始時他有滿血6點,每移動一格他要消耗1點血量。一旦小H的 血量降到 0, 他將死去。 他可以沿路通過拾取鼠標(什麼鬼。。。)來補滿血量。只要他走到有鼠標的格子,他不需要任何時間即可拾取。格子上的鼠標可以瞬間補滿,所以每次經過這個格子都有鼠標。就算到了某個有鼠標的格子才死去, 他也不能通過拾取鼠標補滿 HP。 即使在家門口死去, 他也不能算完成任務回到家中。

地圖上有 5 種格子:

數字 0: 障礙物。

數字 1: 空地, 小H可以自由行走。

數字 2: 小H出發點, 也是一片空地。

數字 3: 小H的家。

數字 4: 有鼠標在上面的空地。

小H能否安全回家?如果能, 最短需要多長時間呢?

輸入格式
第一行兩個整數n,m, 表示地圖的大小爲n*m。

下面 n 行, 每行 m 個數字來描述地圖。

輸出格式
一行, 若小H不能回家, 輸出-1,否則輸出他回家所需最短時間。

輸入輸出樣例
輸入 #1複製
3 3
2 1 1
1 1 0
1 1 3
輸出 #1複製
4
說明/提示
1<=n,m<=9
題目分析:
開始用bfs得了80分發現了這個數據
8 4
3 1 1 1
1 1 1 0
1 1 1 1
0 1 1 2
1 4 4 1
1 4 0 1
1 0 1 1
1 0 1 1
仔細一想確實不行,因爲bfs不會自己選擇既能到達又能不死的路徑,所以就需要優化一下,但沒想通啊!
後來想到可以用dfs再回溯一下暴力的搜索每到達一個點四個方向的走法(注意不回溯的話要麼堵死要麼沒血)。但寫了之後得了90分,又發現了一個數據
7 6
2 0 0 0 0 0
1 0 0 0 0 0
1 1 4 0 0 0
1 0 0 0 0 0
1 1 1 1 1 3
4 0 1 0 4 0
0 0 4 0 0 0
天吶,這題坑也太多了,一個格子可以走多次,並不是平常的走過的格子就不能走了,所以這裏不能用一個二維數組表示一個格子走沒走過!而是要回溯步數!!這樣就可以使一個格子走多次了。
但是,這樣回溯的話不用計算機算就知道要選擇的路徑是非常多的,大數據必定TLE,所以還是要優化一下。
首先,地圖就那麼大,如果步數超過了地圖行列乘積的大小,那麼自然是不行的。所以要保證步數sum<=m*n。
其次,如果你已經到達過一次終點了,那麼最小步數也已經更新過了,那麼你再選擇另外一條路走並且當前步數大於已經更新過的最小步數也是不行的,也就是當前步數sum<=ans(最後要輸出的結果),否則就返回上一層。
代碼:

#include<iostream>
using namespace std;
int n,m,ex,ey;
int tu[101][101];
int d[4][2]={1,0,-1,0,0,1,0,-1};
int ans=9999,sum=0;
void dfs(int,int,int);
int main()
{
    int bx,by;
    cin>>n>>m;
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++)
    {
        if(i==0||i==n+1||j==0||j==m+1)//直接對邊界進行標記,全部賦值爲零
            tu[i][j]=0;
        else cin>>tu[i][j];
        if(tu[i][j]==2) {bx=i;by=j;tu[i][j]=1;}
        if(tu[i][j]==3) {ex=i,ey=j;tu[i][j]=1;}
    }
    tu[bx][by]=0;
    dfs(bx,by,6);
    if(ans==9999) cout<<-1;//如果結果沒有更改,那麼肯定到達不了
    else cout<<ans;//結果更改了就代表到達了
    return 0;
}
void dfs(int x,int y,int hp)
{
    if(hp==0||sum>m*n||sum>ans) return;//沒血了或者步數越界了或者當前步數比當前已知的最小步數大了就返回上一層
    if(x==ex&&y==ey)//到達了家
    {
        ans=min(sum,ans);//選擇最優解
        return;
    }
    if(tu[x][y]==4) hp=6;
    for(int i=0;i<4;i++)
    {
        int xx=x+d[i][0];
        int yy=y+d[i][1];
        if(tu[xx][yy]!=0)
        {
            sum++;//步數加一
            dfs(xx,yy,hp-1);
            sum--;//回溯
        }
    }
}

結果:

輸入:
3 3
2 1 1
1 1 0
1 1 3
輸出:
4
Process returned 0 (0x0)   execution time : 14.257 s
Press any key to continue.
發佈了31 篇原創文章 · 獲贊 27 · 訪問量 8752
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章