演算法系列總結 回溯演算法(解火力網問題)

2021-12-29 20:43:29 字數 2613 閱讀 4274

理論輔助:

回溯演算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。用回溯演算法解決問題的一般步驟為:

1、定義乙個解空間,它包含問題的解。

2、利用適於搜尋的方法組織解空間。

3、利用深度優先法搜尋解空間。

4、利用限界函式避免移動到不可能產生解的子空間。

問題的解空間通常是在搜尋問題的解的過程中動態產生的,這是回溯演算法的乙個重要特性。

還是那個基調,不喜歡純理論的東西,喜歡使用例子來講訴理論,在演算法系列總結:動態規劃(解公司外包成本問題) 的那一節裡面 我們舉得是經典的0-1揹包問題,在回溯演算法裡面也有一些很經典的問題,當然,動態規劃的0-1揹包問題其實也可以使用回溯演算法來解。在諸如此類似的求最優解的問題中,大部分其實都可以用回溯法來解決,可以認為回溯演算法乙個」通用解題法「,這是由他試探性的行為決定的,就好比求乙個最優解,我可能沒有很好的概念知道怎麼做會更快的求出這個最優解,但是我可以嘗試所有的方法,先試探性的嘗試每乙個組合,看看到底通不通,如果不通,則折回去,由最近的乙個節點繼續向前嘗試其他的組合,如此反覆。這樣所有解都出來了,在做一下比較,能求不出最優解嗎?

例子先行,現在我們來看看經典的n後問題

問題描述:在n*n格的棋盤上放置彼此不受攻擊的n個皇后。按照西洋棋的規矩,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。n後問題等價於在n*n格的棋盤上方置n個皇后,任何2個皇后不放在同一行或同一列或同一斜線上。我們需要求的是可放置的總數。

基本思路:   用n元組x[1;n]表示n後問題的解。其中,x[i]表示皇后i放置在棋盤的第i行的第x[i]列。由於不容許將2個皇后放在同一列上,所以解向量中的x[i]互不相同。2個皇后不能放在同一斜線上是問題的隱約束。對於一般的n後問題,這一隱約束條件可以化成顯約束的形式。如果將n*n 格的棋盤看做二維方陣,其行號從上到下,列號從左到右依次編號為1,2,...n。從棋盤左上角到右下角的主對角線及其平行線(即斜率為-1的各斜線)上,2個下標值的差(行號-列號)值相等。同理,斜率為+1的每條斜線上,2個下標值的和(行號+列號)值相等。因此,若2個皇后放置的位置分別是(i,j)和(k,l),且 i-j = k -l 或 i+j = k+l,則說明這2個皇后處於同一斜線上。以上2個方程分別等價於i-k = j-l 和 i-k =l-j。由此可知,只要|i-k|=|l-j|成立,就表明2個皇后位於同一條斜線上。

**:view code

#include  

#include  

#include 

static int n,x[1000]; 

static    long sum; 

int place(int k) 

void backtrak(int t) 

} int main()    }

這段**有必要解釋一下,place(int)即嘗試看是否可以,如果不可以則回退到t+1層,再嘗試其他的組合。

這裡也道出了回溯演算法的核心思想:但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇

演算法實踐:

問題描述:在乙個n*n的網格裡,每個網格可能為「牆壁」(用『x』表示)和「街道」(用『.』表示)。現在在街道放置碉堡,每個碉堡可以向上下左右四個方向**,子彈射程無限遠。牆壁可以阻擋子彈。問最多能放置多少個碉堡,使它們彼此不會互相摧毀。

如下面四張圖,牆壁用黑正方形表示,街道用空白正方形表示,圓球就代表碉堡。1,2,3是正確的,4,5是錯誤的。以為4,5裡面在某一行或者某一列有兩個碉堡,這樣他們就會互相攻擊了。意思明白了嗎?可能我的表達很不清晰,呵呵….

輸入輸出示例

sample input:

4       ——————輸入的n值 

.x.. 

xx..

2  xx 

.x 

3  .x. 

x.x 

.x. 

4  .... 

.... 

.... 

....

sample output:

5  1 

5  4

初拿到這個問題,你會不會想到回溯演算法呢?有人說遍歷牆的位置,然後再牆的上下左右四個格仔放置碉堡會得到最優解,這個我沒有驗證過,細細的用筆畫了畫,好像是這麼回事,但是很多時候要知道最優解用什麼方法是很難發現的,利用通用解題方法回溯法,我們可以在一片茫然的時候開始我們的程式設計

首先我們來分析一下這個問題:使用回溯法,我們嘗試每一種可能放置的情況,然後進行判斷是否滿足要求,若不滿足,嘗試放到下乙個單元格,如此反覆,最終,我們將所有可能放置的情況全部遍歷出來了,連所有情況都出來了,難不成還找不到最優解嗎?哈哈。。說做就做…

view code

#include

char map[4][4];

int best,n;

int canput(int row, int col)

for (i = col - 1; i >= 0; i--)

return 1;

}void solve(int k,int tot)

}else

{x=k/n;

y=k%n;

if((map[x][y]==.) && (canput(x,y) ) )

{map[x][y]=o;

基礎演算法系列總結 回溯演算法(解火力網問題)

理論輔助 回溯演算法也叫試探法,它是一種系統地搜尋問題的解的方法。回溯演算法的基本思想是 從一條路往前走,能進則進,不能進則退回來,換一條路再試。用回溯演算法解決問題的一般步驟為 1 定義乙個解空間,它包含問題的解。2 利用適於搜尋的方法組織解空間。3 利用深度優先法搜尋解空間。4 利用限界函式避免...

前端演算法系列 演算法總結

鍊錶樹 堆map 排序和搜尋 演算法設計思想 七分理解,三分記憶 技巧 三指標 反轉 回文 反轉後相同 中間劈開對稱性 技巧 雙指標 場景 最大 最小值 使用輔助棧,當大於或小於棧頂時才push進去,然後便可取棧頂的值作為最大 小值 煉表處理 合併 刪除 鍊錶反轉 鍊錶成環 完全二叉樹 可以不需要有...

本週小結!(回溯演算法系列三)

本文 已經收錄,裡面還有leetcode刷題攻略 各個型別經典題目刷題順序 思維導圖,可以fork到自己倉庫,有空看一看一定會有所收穫,如果對你有幫助也給乙個star支援一下吧!在回溯演算法 求子集問題 二 中,開始針對子集問題進行去重。本題就是回溯演算法 求子集問題!的基礎上加上了去重,去重我們在...