DFS深度優先遍歷經典例題總結

2021-10-02 14:11:21 字數 4293 閱讀 5454

void

dfs(

int x)

//關於傳入引數問題,根據題意而定,看在題目執行的過程中,哪些是在變得

if(目前已經沒有必要進行下去的條件)

//剪枝操作

//如果傳入的條件,還需要繼續搜下去,分析每一種情況後面跟哪些情況,然後迴圈,每個情況(注意前提:得符合題意)都深搜一下

for(

int i=

1;i<=每種情況數;i++)if

(滿足進一步搜尋條件)

//判斷是否合理}}

}

拿最經典的八皇后問題解釋dfs,正常情況下,如果有乙個6*6的棋盤,在第一行,選擇落子,不考慮規則限制,我們有6種落子方式。

第二行,有1 2 3 4 5 6,6種落子方式。以此類推,6的6次方種情況。

但現在由於規則限制,跟bfs一樣根據流程想出乙個樹出來。指需要按照規則取捨一下那些結點有,哪些沒有即可,搜尋方式上採取遞迴+回溯

從最終結果上,呈現出來的是從根節點一條路走到底,然後撤回底點的上乙個結點,撤回後能走另乙個,就走另乙個

dfs傳入的引數一定要能表示出每個情況的狀態

p1219 八皇后 題目鏈結

乙個如下的 6×6 的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行、每列有且只有乙個,每條對角線(包括兩條主對角線的所有平行線)上至多有乙個棋子。

上面的布局可以用序列 2 4 6 1 3 5 來描述,第 ii 個數字表示在第 ii 行的相應位置有乙個棋子,如下:

行號 1 2 3 4 5 6

列號 2 4 6 1 3 5

這只是棋子放置的乙個解。請編乙個程式找出所有棋子放置的解。

並把它們以上面的序列方法輸出,解按字典順序排列。

請輸出前 33 個解。最後一行是解的總個數。

輸入格式

一行乙個正整數 nn,表示棋盤是 n \times nn×n 大小的。

輸出格式

前三行為前三個解,每個解的兩個數字之間用乙個空格隔開。第四行只有乙個數字,表示解的總數。

輸入輸出樣例輸入6

輸出2 4 6 1 3 5

3 6 2 5 1 4

4 1 5 2 6 3

4說明/提示

【資料範圍】

對於 100%100% 的資料,6 ≤n≤13。

思路就是深搜加回溯,技巧就是對於斜對角線上面是否有結點的判別,算一下就知道,左下到右上斜對角線i+j=固定值,左上到右下i-j+n=固定值

按照深搜的思想進行分析,在題目執行過程中,所腦補出的樹形結構,什麼在改變。開始乙個棋盤上面,什麼都沒放,在第一行上可以放1 2 3 4 5 6位置。

如果選取1,對1深搜結果如下,選擇2,3都一樣。

下一步,第二行,1已經被放過,可以放2 3 4 5 6,放2位置不行,3位置可以

下一步,從3行2列開始。。。。。。。

過程中可以發現,改變是行數,第一行每個可能深搜第二行,第二行每個可能深搜第三行。

ac**

#include

using

namespace std;

int p[

100]

;//儲存路徑

int visy[

100]=;

//記錄列是否訪問

int vxie1[

100]=;

//記錄左下到右上斜線是否訪問

int vxie2[

100]=;

//左上到右下

int n;

//n*n棋盤

int total=0;

//記錄搜尋到結果總數

void

dfs(

int x)

//如果x=n表示已經搜到最後一行,total++,一條路走到盡頭

//否則這一行,有n種情況,如果符合題意,每個情況繼續深搜

for(

int j=

0;j}int

main()

資源限制

時間限制:1.0s 記憶體限制:256.0mb

問題描述

n個人參加某項特殊考試。

為了公平,要求任何兩個認識的人不能分在同乙個考場。

求是少需要分幾個考場才能滿足條件。

輸入格式

第一行,乙個整數n(1這題因為我比較笨,所以想了很久才想通。同樣是分析題目進行過程腦補出樹或圖。

第一步。所有房間都是空的,放裡面放人,放第乙個人

第二步。放第二個人,如果與第乙個房間所有人沒關係,放第乙個房間,否則新開乙個房間,放進去。

第三步,放第三個人,如果1,2房間不能放,開乙個房間放到3號房間,否則放在1或2房間

第四步。。。。

分析過程可以看出,每次房間數是在變化,每次放的人的編號也在變化。意思就是樹的每個點,都包含我現在放入編號幾,我用了多少個房間,在每個點裡搜出最佳點。

ac**

#include

using

namespace std;

int n,m,min_num;

int mp[

102]

[102]=

};int r[

102]

[102]=

};void

dfs(

int x,

int num)

//如果已經安排完,比較後更新最少房間數

//八皇后一樣到x行,都會有n種情況。對於此題到達分配編號x,有num個房間

for(

int i=

1;i<=num;i++)}

//找不到合適的房間,就開乙個新的房間繼續深搜,**就是把流程寫了一遍

r[num+1]

[0]=x;

dfs(x+

1,num+1)

; r[num+1]

[0]=

0;}int

main()

dfs(1,

0);printf

("%d\n"

,min_num)

;}

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

思路這道題也可以用bfs做,每個結點有四處走向,不斷地擴散,找到終點,返回

但是記錄能有幾條路比較麻煩

用dfs思路和前兩題一樣,按照題目過程腦補出樹

第一步,在起點,有4種情況,如果可以,上下左右都深搜一下(如果選擇深搜右)

第二步,起點的右節點為起點,上下左右如果可以的話,都深搜(如果可以還選擇右)

第三步,起點的右的右,上下左右,都深搜,。。。。還選右的話

如果題意允許,就一直講走完到了終點,遞迴出口讓total++就行

ac**

就沒有注釋太多了,跟前面差不多

#include

using

namespace std;

int n,m,t,total=0;

//n行,m列,t個障礙物

int sx,sy,x2,y2;

//起點x,y,終點x,y

int mp[10]

[10]=

};int vis[10]

[10]=

};int dir[4]

[2]=

,,,}

;void

dfs(

int x,

int y)

for(

int i=

0;i<

4;i++)}

}int

main()

dfs(sx,sy)

;printf

("%d\n"

,total)

;}

總結完畢!

深度優先搜尋(DFS)例題

dfs概念 它從某個狀態開始,不斷地轉移狀態直至無法轉移,然後回退到前一步的狀態,繼續轉移其他狀態,如此不斷重複,直至找到最終的解。解題利用的是 遞迴函式。例題 dfs 例題 給定整數a1,a2,a3.an,判斷是否能夠從中抽出幾個整數使得它們的和剛好為k int a max int n,k boo...

深度優先遍歷DFS

本文章 中的圖用鄰接矩陣來表示,所以演算法複雜度為o v 2 如果用鄰接表來表示,那麼演算法的複雜度為o v e dfs可用來判斷圖中是否有環,展現無向圖中的連通分支。通過dfs,形成乙個由多棵深度優先樹所組成的深度優先森林。將原先圖中的邊新增到該森林之後,可以將所有邊定義為以下四類 1.樹邊 森林...

深度優先遍歷(DFS)

深度優先搜尋是一種列舉所有完整路徑以遍歷所有情況的搜尋方法。使用遞迴可以很好的實現深度優先遍歷,因此,只能說遞迴是實現深度優先遍歷的一種實現方式。給定乙個序列,列舉這個序列所有的子串行 例如子串行包含,選擇最優子串行,使它的某個特徵是所有子串行中最優的。這個問題也就是從n個整數中,選擇k個數的所有方...