1. 程式人生 > >淺談回溯與深度優先搜尋

淺談回溯與深度優先搜尋

搜尋與回溯是計算機競賽中常用的演算法,當很多問題無法通過計演算法則來求解時,便可以利用搜索和回溯的技術來求解。
回溯是搜尋演算法中的一種控制策略,它的基本思想是:為了求得問題的解,先選擇一種可能的情況向前探索,如果在探索過程中發現原來的選擇是錯誤的,就退回一步重新選擇,如此反覆進行,直到窮舉出所有情況,可以證明該問題無解。

我相信很多人小時候都玩過“走迷宮”這樣一個遊戲:進入迷宮後,先隨意選擇一個可以走的地方前進,如果碰到死路,則說明前方無路可走,這時,如果周圍還有沒有路可以走,就繼續選擇一條路前進,否則就往後退一步,再看看周圍有沒有路可走……如此反覆進行下去直到到達出口或退回起點為止。而走迷宮的這個過程,便是一個搜尋與回溯。

這裡寫圖片描述
如圖所示,以深度優先的方式進行遍歷,假設起點是1,訪問順序為1 -> 2 -> 4,由於結點4沒有未訪問的相鄰結點,所以這裡需要回溯到2,然後發現2還有未訪問的相鄰結點5,於是繼續訪問2 -> 5 -> 6 -> 3 -> 7,這時候7回溯到3,3回溯到6,6回溯到5,5回溯到2,最後2回溯到起點1,1已經沒有未訪問的結點了,搜尋終止,圖中圓圈代表路點,紅色箭頭表示搜尋路徑,藍色虛線表示回溯路徑。

講完演算法的原理,我們來講講怎麼用程式碼實現:

int dfs(int k)
{
    for (int i=1;i<=可能的總數;i++)
      if
(滿足要求) { 儲存結果 if (到達目標) 輸出解; else dfs(k+1); 回溯:變回最初的狀態 } }

因為遞迴呼叫需要使用系統棧並且系統棧的大小一般只有8M,所以當我們的搜尋次數太多,函式的呼叫次數太多時,函式所使用的系統棧便會溢位(俗稱“爆了”)。這時應該怎麼辦呢?

解決這種問題,一般有兩種方案:剪枝和使用人工棧。

所謂剪枝,就是減少搜尋的次數,如果已知繼續走下去無法到達目標或無法得到最優解時,便不再繼續往下搜尋,退回一步。

接下來我們講講怎麼使用人工棧

tot=1
; while (tot>0) { do a[i]++;//這裡我們定義a[i]為第i步的選擇 while(不可行但可換); if (不能換) tot--;//退後一步 else if (未達到目標) tot++;//繼續搜尋 else 輸出; }

講了這麼多,還是來到例題吧!

洛谷 P1605 迷宮

傳送至原題>>
題目大意:
有N*M的迷宮,共有T處障礙,給定起點座標和終點座標,每個方格最多經過1次,問有多少種從起點座標到終點座標的方案。在迷宮中移動有上下左右四種方式,每次只能移動一個方格。資料保證起點上沒有障礙。

輸入格式

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

輸出格式

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

樣例輸入

2 2 1
1 1 2 2
1 2

樣例輸出

1

思路:

就跟我最開始講的那樣,不斷搜尋,如果到達終點,總方案數加一。因為每個格子只能走一次,所以每次到達一個格子就要標記一下。注意回溯時要取消標記。

下面貼上程式碼

#include <cstdio>
int map[20][20];//map表示可不可以走,所以既可以標記障礙物也可以標記有沒有走過
int ans,n,m,t,x1,y1,x2,y2;
int a[4]={0,0,1,-1};//方向適量
int b[4]={1,-1,0,0};
void dfs(int x,int y)
{
    for (int k=0;k<4;k++)
      if (map[x+a[k]][y+b[k]]==0&&x+a[k]<=n&&x+a[k]>=1&&y+b[k]<=m&&y+b[k]>=1) //注意判越界。可以在最外層加障礙物,但我還是打的if語句
        {
            map[a[k]+x][b[k]+y]=1;
            if (a[k]+x==x2&&b[k]+y==y2) ans++; else dfs(a[k]+x,b[k]+y);//到達目標就計數器加一,否則就繼續走
            map[a[k]+x][b[k]+y]=0;//注意取消標記
        }
}
int main()
{
    scanf("%d%d%d",&n,&m,&t);
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    for (int i=1;i<=t;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        map[x][y]=1;//標記障礙物
    }
    map[x1][y1]=1;//初始座標已經到達
    dfs(x1,y1);
    printf("%d",ans);
    return 0;
}

好了,我們的回溯與深度優先搜尋也就結束了

喜歡的請點贊,謝謝!

相關推薦

回溯深度優先搜尋

搜尋與回溯是計算機競賽中常用的演算法,當很多問題無法通過計演算法則來求解時,便可以利用搜索和回溯的技術來求解。 回溯是搜尋演算法中的一種控制策略,它的基本思想是:為了求得問題的解,先選擇一種可能的情況向前探索,如果在探索過程中發現原來的選擇是錯誤的,就退回一步

廣度優先搜尋深度優先搜尋

廣度優先搜尋(寬度優先搜尋,BFS)和深度優先搜尋(DFS)演算法的應用非常廣泛,本篇文章主要介紹BFS與DFS的原理、實現和應用。 深度優先搜尋 圖的深度優先搜尋(Depth First Search),和樹的先序遍歷比較類似。 它的思想:假設初始狀態是圖中所

深度優先搜尋(DFS)

一,定義         一個人走進了迷宮,到達甲路口時,他面前有Ñ條路,他選擇了其中的一條,走了一會後到達乙路口,面前又出現Ñ條路,他又選擇了其中的一條,走了一會發現走不通,於是他退回到乙路口又

演算法——走迷宮問題廣度優先搜尋

本文始發於個人公眾號:**TechFlow**,原創不易,求個關注 在之前週末LeetCode專欄當中,我們詳細描述了深度優先搜尋和回溯法,所以今天我們繼續這個話題,來和大家聊聊搜尋演算法的另一個分支,廣度優先搜尋。 廣度優先搜尋的英文是Breadth First Search,簡寫為bfs。與它相對的深

python 遞迴深度優先搜尋廣度優先搜尋演算法模擬實現

一、遞迴原理小案例分析 (1)# 概述 遞迴:即一個函式呼叫了自身,即實現了遞迴 凡是迴圈能做到的事,遞迴一般都能做到! (2)# 寫遞迴的過程 1、寫出臨界條件2、找出這一次和上一次關係3、假設當前函式已經能用,呼叫自身計算上一次的結果,再求出本次的結果 (3)案例分析:求1+2+3+…+n的數和

深度優先搜尋遍歷廣度優先搜尋遍歷

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

深度優先搜尋和廣度優先搜尋的比較分(轉)

深度優先搜尋和廣度優先搜尋的深入討論   (一)深度優先搜尋的特點是: (1)無論問題的內容和性質以及求解要求如何不同,它們的程式結構都是相同的,即都是深度優先演算法(一)和深度優先演算法(二)中描述的演算法結構,不相同的僅僅是儲存結點資料結構和產生規則以及輸出要求。

LeetCode-105.從前序中序遍歷序列構造二叉樹(相關話題:深度優先搜尋

根據一棵樹的前序遍歷與中序遍歷構造二叉樹。 注意: 你可以假設樹中沒有重複的元素。 例如,給出 前序遍歷 preorder = [3,9,20,15,7] 中序遍歷 inorder = [9,3,15,20,7] 返回如下的二叉樹: 3 / \ 9

LeetCode-106.從中序後序遍歷序列構造二叉樹(相關話題:深度優先搜尋

根據一棵樹的中序遍歷與後序遍歷構造二叉樹。 注意: 你可以假設樹中沒有重複的元素。 例如,給出 中序遍歷 inorder = [9,3,15,20,7] 後序遍歷 postorder = [9,15,7,20,3] 返回如下的二叉樹: 3 / \

深度優先搜尋(DFS)廣度優先搜尋(BFS)

深度優先搜尋的基本模型 void dfs(int step) { 判斷邊界 嘗試每一種可能 for(int i=0; i<n; i++) { 繼續下一步 dfs(step+1); } 返回 } 輸出一個

深度優先搜尋全排列

      做題過程中我們經常會遇到這樣的問題: 輸入一個數n,輸出1-n的全排列。可能很多人會想到列舉暴力,這裡給大家介紹一種演算法:深度優先搜尋 在這裡舉個簡單的例子         假如有編號為1 、2、3 的3 張撲克牌和編號為l 、2 、3 的3 個盒子。 現在需

深度優先搜尋(DFS)遞迴非遞迴實現邏輯詳解

 遞迴與非遞迴:        資料結構對於學習程式設計的人來說是非常重要的,我們在現實生活碰到的各種煩難問題可以用遞迴來實現,一個遞迴思想就把問題給簡單化了,但是我們都知道遞迴是非常耗時的,一旦資料量龐大起來,遞迴

“生動”講解——深度優先搜尋廣度優先搜尋

深度優先搜尋(Depth First Search,DFS) 主要思想:不撞南牆不回頭 深度優先遍歷的主要思想就是:首先以一個未被訪問過的頂點作為起始頂點,沿當前頂點的邊走到未訪問過的頂點;當沒有未訪問過的頂點時,則回到上一個頂點,繼續試探訪

廣度優先搜尋深度優先遍歷

廣度優先搜尋有一個有向圖如圖a:                                                   圖a廣度優先搜尋的策略是:假設我們以頂點0為原點進行搜尋,首先確定鄰接0的頂點集合S0 = {1,2},然後確定頂點1的集合S1 = {3},

Python實現深度優先寬度優先搜尋演算法

實驗目的:瞭解和掌握深度優先和寬度優先演算法的原理以及應用並實現兩種演算法。實驗內容:1. 演算法原理首先,我們給定一個二叉樹圖如下: 1). 寬度優先搜尋:寬度優先搜尋演算法(Breadth First Search,BSF),思想是:· 1.從圖中某頂點v出發,首先訪問定

圖的儲存(鄰接表)建立深度優先、廣度優先搜尋

#pragma once #include<iostream> #include<queue> using namespace std; #define Vnum 10 typedef int DATA; /*鄰接表儲存圖*/ typedef str

深度優先搜尋原理實踐(java)

概論 深度優先搜尋屬於圖演算法的一種,是一個針對圖和樹的遍歷演算法,英文縮寫為 DFS 即 Depth First Search。深度優先搜尋是圖論中的經典演算法,利用深度優先搜尋演算法可以產生目標圖的相應拓撲排序表,利用拓撲排序表可以方便的解決很多相關的圖論問題,如最大路徑問題等等。一般用堆資料結構來輔

圖解:深度優先搜尋廣度優先搜尋及其六大應用

![](https://user-gold-cdn.xitu.io/2020/7/11/1733b79728a2b9c2?w=900&h=372&f=png&s=446352) > 圖演算法第二篇 深度優先搜尋與廣度優先搜尋及其應用 > 約定:本文所有涉及的圖均為無向圖

angular2angularJS的區別

iges style 區別 float 頁面加載速度 小夥伴 困境 特征 架構 簡介 大家好,今天給大家介紹一下angular,相信做過前端的小夥伴們都知道angular的大名,angularJS自2012年發布起就受到了大家的廣泛關註。他首次提出

jdbcTemplatemybatis

root true method per .get utf alibaba void tweene Spring對數據庫的操作在jdbc上面做了深層次的封裝,也就是工具類 jdbcTemplate 作用: 1: 它提供了AOP式的事務管理 AOP式的事物管理:在以前的事務管