迷宮問題(回溯思想)

題目鏈接:https://www.luogu.org/problem/P1605

題目背景:

給定一個N*M方格的迷宮,迷宮裏有T處障礙,障礙處不可通過。給定起點座標和終點座標,問: 每個方格最多經過1次,有多少種從起點座標到終點座標的方案。在迷宮中移動有上下左右四種方式,每次只能移動一個方格。數據保證起點上沒有障礙。

輸入格式:
第一行N、M和T,N爲行,M爲列,T爲障礙總數。第二行起點座標SX,SY,終點座標FX,FY。接下來T行,每行爲障礙點的座標。

輸出格式:
給定起點座標和終點座標,問每個方格最多經過1次,從起點座標到終點座標的方案總數。

輸入輸出樣例
輸入 #1

2 2 1
1 1 2 2
1 2

輸出 #1

1

說明/提示
【數據規模】

1≤N,M≤5


分析:此題採用回溯的思想

1. 回溯算法概念:

        回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回,嘗試別的路徑。

        回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。

        許多複雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。

2. 回溯法的基本思想

        在包含問題的所有解的解空間樹中,按照深度優先搜索的策略,從根結點出發深度探索解空間樹。當探索到某一結點時,要先判斷該結點是否包含問題的解,如果包含,就從該結點出發繼續探索下去,如果該結點不包含問題的解,則逐層向其祖先結點回溯。(其實回溯法就是對隱式圖的深度優先搜索算法)。

        若用回溯法求問題的所有解時,要回溯到根,且根結點的所有可行的子樹都要已被搜索遍才結束。

3. 回溯法遞歸框架

回溯法是對解空間的深度優先搜索,在一般情況下使用遞歸函數來實現回溯法比較簡單,其中i爲搜索的深度,框架如下:

1: int a[n];
2: try(int i)
3: {
4:     if(i>n)
5:         輸出結果;
6:     else
7:     {
8:         for(j = 下界; j <= 上界; j=j+1) // 枚舉i所有可能的路徑
9:         {
10:             if(fun(j)) // 滿足限界函數和約束條件
11:             {
12:                 a[i] = j;
13:                 ... // 其他操作
14:                 try(i+1);
15:                 回溯前的清理工作(如a[i]置空值等);
16:             }
17:         }
18:     }
19: }

c++代碼實現:

#include <iostream>
using namespace std;
int pic[6][6];
int dx[4] = {0, 0, -1, 1};
int dy[4]= {-1, 1, 0, 0};
int ans = 0; //計算總的路徑數
int N,M,T;
int SX, SY;
int FX, FY;
int temp[6][6];
void dfs(int x,int y)
{
    if(x==FX && y == FY)
    {
        ans++;
        return;
    }
    else
    {
        for(int i=0;i<4;i++)
        {
            if(temp[x+dx[i]][y+dy[i]] == 0 && pic[x+dx[i]][y+dy[i]]==1)
            {
                temp[x][y] = 1;
                dfs(x+dx[i], y+dy[i]);
                temp[x][y] = 0;
            }
        }
    }

}
int main()
{
    cin>>N>>M>>T;
    for(int i=1;i<=N;i++)
    {
        for (int j = 1; j <= M; j++)
        {
            pic[i][j] = 1;
        }
    }
    cin>>SX>>SY;
    cin>>FX>>FY;
    for(int i=0;i<T;i++)
    {
        int t1,t2;
        cin>>t1>>t2;
        pic[t1][t2] = 0;
    }
    dfs(SX, SY);
    cout<<ans<<endl;
    return 0;
}

python3代碼實現:

# dx = [0, 1, 0, -1]
# dy = [1, 0, -1, 0]
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
INIT_ROW = 100
INIT_COL = 100

def walk(x, y):
    global count
    if x == EX and y == EY:
        count += 1
        return
    else:
        for i in range(4):

            if temp[x + dx[i]][y + dy[i]] == 0 and pic[x + dx[i]][y + dy[i]] == 1:
                temp[x][y] = 1
                walk(x + dx[i], y + dy[i])
                temp[x][y] = 0


if __name__ == '__main__':

    s1 = list(map(int, input().split(' ')))
    N, M, T = s1[0], s1[1], s1[2]

    s2 = list(map(int, input().split(' ')))
    SX, SY, EX, EY = s2[0], s2[1], s2[2], s2[3]

    pic = []
    temp = []
    for i in range(INIT_ROW):
        pic.append([0 for i in range(INIT_ROW)])
        temp.append([0 for i in range(INIT_COL)])
    for i in range(1, N+1):
        for j in range(1, M+1):
            pic[i][j] = 1
    for k in range(T):
        row = list(map(int, input().split(' ')))
        pic[row[0]][row[1]] = 0
    print(pic)
    print(temp)
    count = 0
    walk(SX, SY)
    print(count)

參考鏈接:https://www.bilibili.com/video/av36473519/?p=2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章