關於DFS 深度優先搜尋)

2021-10-10 18:15:45 字數 3180 閱讀 2637

一年前開始接觸c語言 後來學了演算法 因為沒堅持下來就放棄了一段時間,現在想重新撿起來,就算不為了拿下什麼獎,也為了自己以後能說起來我也堅持過學一些東西。

先說說為什麼寫dfs吧,最近打了場比賽,dfs題很多,突然就想到搜尋演算法在比賽中很常用,學會用的話很多題都很好寫,所以今天又去學了一下。

下面先把題掛一下:

這是一道簡單的:

其實就是乙個簡單的迷宮,入口是s,出口是e,#為不能走的路,輸出的最短時間就是最短路,直接掛**。

#include

#include

#include

#include

int min =

9999999

;int c[4]

[2]=

,,,}

;//上下左右四個方向

int m,n,r,t,q,w;

//m,n為行,列 r,t為終點座標,q,w為起點座標

char s[

1000][

1000];

void

dfs(

int x,

int y,

int step)

for(i =

0; i <

4; i++)if

(s[xn]

[yn]==0

)//0為可以走

}return;}

intmain()

getchar()

;}for(i =

0; i < m; i++

)else

if(s[i]

[j]==

'.')

else

if(s[i]

[j]==

'#')

//不可走的置為1

else

if(s[i]

[j]==

'e')}}

dfs(q, w,0)

;//從起點開始搜尋

printf

("%d"

, min)

;//最短路徑

}

這裡我是把符號都置為0和1,將地圖改變了一下。

相信大家都看得懂,下面開始寫我對dfs的理解:

1.深度優先搜尋,顧名思義,深度,我的理解就是一條路走到底,當深到不能再深了,我再退回來換條路深,直到沒路可以換即走完了所有情況,所以也叫暴力搜尋。

3.因為是窮舉所有情況,所以有時時間複雜度較高,至於如何改變,就涉及到dfs的剪枝,這裡先了解一下這個詞,具體我會在下面解釋。

下面掛乙個我在我喜歡的博主那裡拿來的樹,觀察一下dfs究竟是怎麼以深度搜尋的:

然後這個搜尋的順序就是

a->b->e->b->f->c->f->b->c->b->a->c->a->d->g->d->a

你可能會問,為什麼我b->f->c已經到過了c,回溯到b後還要再去c呢,其實很容易想明白,如果c是終點,那最短路當然不是a->b->f->c,當然是a->c,那這是怎麼做到的呢,這一點我在上面**上也有掛出,回溯後置為零的操作,這樣的話避免了因此錯過更優解法。還有乙個問題,那我到達c之後,為什麼不走a呢,顯而易見,那不就成環了嗎,你現在還處於走過a的狀態,a值為1,所以不能走。這樣也避免了無限迴圈搜尋的結果。這裡提一句最優化剪枝,如果我已經得到了a->c這條長度為2的路,那在之後所有路徑只要大於二,也就是說如果我走了兩步還沒到終點,我就不走了,我就要回到第一步再找其他的路了,這樣就省下了很多無用的搜尋。

然後再掛乙個不一樣的dfs:

很容易理解就是用最少的炸彈數炸掉3x3方格中所有的』e』,每個炸彈可以炸上下左右以及中間五個格,炸彈放的位置是隨意的,所以我們可以把每乙個位置放不放炸彈的所有情況全部列出來,即有2的九次方為512種情況,用dfs的話可以很快算出,下面看**:

#include

intmin

(int a,

int b)

//三目運算子寫函式

const

int dir[4]

[2]=

,,,}

;//上下左右

int atack[5]

[5];

//記錄每個位置被炸彈波及次數

char mp[5]

[5];

//地圖

int ans =

1e9;

void

dfs(

int x,

int y,

int bomb)

++atack[x]

[y];

//投放炸彈的情況

for(

int i =

0; i <

4; i++)if

(y ==3)

dfs(x +1,

1, bomb +1)

;//換下一行,使用炸彈,炸彈數加1

else

dfs(x, y +

1, bomb +1)

;//換下一列

--atack[x]

[y];

//不投放炸彈的情況

for(

int i =

0; i <

4; i++)if

(y ==3)

dfs(x +1,

1, bomb)

;//不投放炸彈,炸彈數不變

else

dfs(x, y +

1, bomb);}

intmain()

比上一題稍難一點,仔細看dfs的使用情況也不難理解,也就是記錄下每乙個位置投炸彈與不投炸彈的所有情況,再進行比較選出最少炸彈數的情況輸出。

剪枝:剪枝就是通過一些判斷,剪掉一些不必要的子樹,因為這個分枝上都不是我們想要的結果,就沒必要再去搜尋它了。比如,在走迷宮時,如果發現當前的步數已經超過了最優步數,那從這個狀態開始的搜尋全都多餘了,就可以省去大量的搜尋。還有一些重複性剪枝之類的都與此類似,就不在這裡多說了。

以後再有有趣的題我還是會掛上來的,可以繼續關注。

深度優先搜尋DFS

作為搜尋演算法的一種,dfs對於尋找乙個解的 np 包括npc 問題作用很大。但是,搜尋演算法畢竟是 時間複雜度是o n 的階乘級演算法,它的效率比較低,在資料規模變大時,這種演算法就顯得力不從心了。關於深度優先搜尋的效率問題,有多種解決方法。最具有通用性的是剪枝 prunning 也就是去除沒有用...

深度優先搜尋 DFS

深度優先搜尋 縮寫dfs 有點類似廣度優先搜尋,也是對乙個連通圖進行遍歷的演算法。它的思想是從乙個頂點v 0開始,沿著一條路一直走到底,如果發現不能到達目標解,那就返回到上乙個節點,然後從另一條路開始走到底,這種盡量往深處走的概念即是深度優先的概念。你可以跳過第二節先看第三節,還是引用上篇文章的樣例...

深度優先搜尋(dfs)

深度優先搜尋的一般步驟 1 從頂點v出發,訪問v。2 找出剛才訪問過的頂點的第乙個未被訪問的鄰接點,訪問該頂點。以該頂點為新頂點,重複此步驟,直到剛訪問的頂點沒有沒有未被訪問過的鄰接點為止。3 返回前乙個訪問過的仍有未被訪問過的鄰接點的頂點,找出該頂點的下乙個未被訪問過的鄰接點,訪問該頂點。4 重複...