回溯演算法以及剪枝問題理解

2021-10-24 11:43:39 字數 2023 閱讀 3280

程式呼叫自身的程式設計技巧稱為遞迴。
舉例說明一下:

public void recursion(int n)

}

當n=2的時候首先執行recursion(2),接著執行recursion(1),最後結果就是1和2。

遞迴的呼叫實質就像是乙個堆疊,當我們執行recursion(2)的時候發現無法得到結果並且接著執行recursion(1),此時就相當於把recursion(2)存入棧中,然後執行完recursion(1)的再從棧中取出recursion(2)執行得到結果。

如果是for迴圈加上遞迴呢

public void recursion(int n)}}

對於這種問題,我個人認為乙個很好的辦法就是去分層理解。

recursion(2)-> 輸出次數:3^1

呼叫3次recursion(1)

輸出三次2

每一次的recursion(1)-> 輸出次數:3^2

呼叫3次recursion(0)

輸出三次1

給定兩個整數 n 和 k,返回 1 … n 中所有可能的 k 個數的組合。

示例

輸入: n = 4, k = 2

輸出:[

[2,4],

[3,4],

[2,3],

[1,2],

[1,3],

[1,4],

]分析:

首先可以看出是乙個組合問題

對於例題來看

1.如果組合裡有 1 ,那麼需要在 [2, 3, 4] 裡再找 1 個數;

2.如果組合裡有 2 ,那麼需要在 [3, 4] 裡再找 1數。注意:這裡不能再考慮 1,因為包含 1 的組合,在第 1 種情況中已經包含。

所以這裡使用回溯演算法,首先畫出遞迴樹

然後通過遞迴操作繼續取數,只需注意在取下乙個數時要捨去不需要的數

public class solution 

// 我們取數是從1開始取

dequepath = new arraydeque<>();

dfs(n, k, 1, path, res);

return res;

}private void dfs(int n, int k, int begin, dequepath, list> res)

// 從1開始取數

for (int i = begin; i <= n; i++) }}

初步完成後發現**可以進行優化(剪枝操作)

例如這個立體中當我們取的第乙個數為4的時候以及沒有意義了,因為第二個數無論取什麼都已經重複了。

繼續分析:如果n=8,k=5時,從5開始搜尋就沒有意義了,因為把5選上後面6,7,8也組不成5個數了。

所以:

當path.size()==1時,還需要選4個數,最大搜尋起點為5

當path.size()==2時,還需要選3個數,最大搜尋起點為6

當path.size()==3時,還需要選2個數,最大搜尋起點為7

當path.size()==4時,還需要選1個數,最大搜尋起點為8

根據上面可以看出n = 還需要選擇的個數 + 最大搜尋起點 + 1

所以我們可以把迴圈的上界限制為n - 還需選擇的個數 + 1

即 for迴圈修改為i < n - (k - path.size()) + 1;

for (int i = begin; i <= n - (k - path.size()) + 1; i++)

數獨遊戲(sudoku)演算法 回溯 剪枝

具體數獨遊戲是什麼,我就不介紹了,好像多餘了,你能來看這篇文章,說明你對數獨遊戲已經有了相當的了解了!還是入正題吧,今天先講解和發下用回溯 剪枝 求數獨遊戲,我也看了些回溯 剪枝求數獨的演算法,很惱火,既沒注釋,而且演算法沒有通用性。今天我給大家講的回溯 剪枝法,不僅可以用於解決數獨問題,而且還可以...

演算法訓練 剪格仔(dfs 剪枝 回溯)

題目描述 如下圖所示,3 x 3 的格仔中填寫了一些整數。10 1 52 20 30 1 1 2 3 我們沿著圖中的星號線剪開,得到兩個部分,每個部分的數字和都是 60。本題的要求就是請你程式設計判定 對給定的 m x n 的格仔中的整數,是否可以分割為兩個部分,使得這兩個區域的數字和相等。如果存在...

DFS 回溯與剪枝 C N皇后問題

c n皇后問題 在n n的方格棋盤放置了n個皇后,使得它們不相互攻擊 即任意2個皇后不允許處在同一排,同一列,也不允許處在與棋盤邊框成45角的斜線上。你的任務是,對於給定的n,求出有多少種合法的放置方法。input共有若干行,每行乙個正整數n 10,表示棋盤和皇后的數量 如果n 0,表示結束。out...