有時會遇到這樣一類題目,它的問題可以分解,但是又不能得出明確的動態規劃或是遞迴解法,此時可以考慮用回溯法解決此類問題。回溯法的優點 在於其程式結構明確,可讀性強,易於理解,而且通過對問題的分析可以大大提高執行效率。但是,對於可以得出明顯的遞推公式迭代求解的問題,還是不要用回溯 法,因為它花費的時間比較長。
回溯法的基本思想
回溯法中,首先需要明確下面三個概念:
(二)狀態空間樹:剛剛已經提到,狀態空間樹是乙個對所有解的圖形描述。樹上的每個子節點的解都只有乙個部分與父節點不同。
(三)擴充套件節點、活結點、死結點:所謂擴充套件節點,就是當前正在求出它的子節點的節點,在dfs中,只允許有乙個擴充套件節點。活結點就是通過與約束函式的對照,節點本身和其父節點均滿足約束函式要求的節點;死結點反之。由此很容易知道死結點是不必求出其子節點的(沒有意義)。
深度優先搜尋(dfs)和廣度優先搜尋(fifo)
在 分支界限法中,一般用的是fifo或最小耗費搜尋;其思想是一次性將乙個節點的所有子節點求出並將其放入乙個待求子節點的佇列。通過遍歷這個佇列(佇列在 遍歷過程中不斷增長)完成搜尋。而dfs的作法則是將每一條合法路徑求出後再轉而向上求第二條合法路徑。而在回溯法中,一般都用dfs。為什麼呢?這是因 為可以通過約束函式殺死一些節點從而節省時間,由於dfs是將路徑逐一求出的,通過在求路徑的過程中殺死節點即可省去求所有子節點所花費的時間。fifo 理論上也是可以做到這樣的,但是通過對比不難發現,dfs在以這種方法解決問題時思路要清晰非常多。
因此,回溯法可以被認為是乙個有過剪枝的dfs過程。
利用回溯法解題的具體步驟
首先,要通過讀題完成下面三個步驟:
(1)描述解的形式,定義乙個解空間,它包含問題的所有解。
(2)構造狀態空間樹。
(3)構造約束函式(用於殺死節點)。
然後就要通過dfs思想完成回溯,完整過程如下:
(1)設定初始化的方案(給變數賦初值,讀入已知資料等)。
(2)變換方式去試探,若全部試完則轉(7)。
(3)判斷此法是否成功(通過約束函式),不成功則轉(2)。
(4)試探成功則前進一步再試探。
(5)正確方案還未找到則轉(2)。
(6)已找到一種方案則記錄並列印。
(7)退回一步(回溯),若未退到頭則轉(2)。
(8)已退到頭則結束或列印無解。
回溯法的資料結構
回溯法的狀態空間樹,在計算機上的資料結構有兩種表示方法。當用k表示樹的節點層數,n表示節點總數,m表示解的總數時:
(一)用m個k元組表示m種不同的解。其中,每組中的元素是[1,n]中的乙個元素。在pascal中,可以這樣定義變數:
var a:array[1..k,1..m]of integer;(integer可以依n的範圍決定)
(二)用m個n元組表示m種不同的解。因為所有的節點都包含在每個解的表示中,每組中的元素只有兩種情況,被選用和不被選用。在pascal中,可以這樣定義變數:
var a:array[1..n,1..m]of boolean;
這兩種資料結構的解空間最多都含有2n個不同的元組
#include
using namespace std;
int str=;
bool bo[7];
long xnum=0;
/*
int print(int i)
#include
#include
#define max_length 100 /*集合的最大元素個數*/
void powerset(char*, int, char*,int *);
int main()
; /*儲存集合的冪集元素*/
int numofpowerset=0; /*冪集元素記數*/
printf("input the elements:");
scanf("%s",a);
printf("----------------------------/n");
powerset(a,0,set,&numofpowerset); /*呼叫遞迴函式*/
printf("----------------------------/n");
printf("number of powerset: %d/n",numofpowerset);
return 1;}/*
引數說明: char* a : 待求冪集的集合
int i : 當前分析到集合的第i個元素
char* set : 儲存當前冪集元素狀態
int* num : 冪集元素記數
*/void powerset(char* a, int i, char* set, int * num)
/n",set);
(*num)++;
}else}/*
輸入測試資料:abcd,表示集合,得到輸出資料如下:input the elements:abcd
-------------------------
{}-------------------------number of powerset: 16
*/
字串總結 字串錯題集
字串方法中不會改變原陣列的方法 concat slice substr substring trim touppercase replace split join 得到字元的字元編碼 str.charcodeat i 下標為i的字元的編碼從字串中查詢子字串的方法 str.indexof str.la...
shell字串操作集
宣告 以下內容來自網際網路 1 如果去掉字串後面的 例如 a b c 如何變成 a b c 用乙個土的辦法 x a b c echo x awk f 效果 root x x a b c root x echo x awk f a b c 達到了目的,但感覺不爽,請更好方法 sed s g ufile...
delphi字串操作集
delphi字串操作集 1.copy 字串的複製操作,有3個引數 copy 源資料,複製起始位置 含 複製長度 2.leftstr rightstr 所在單元 strutils 功能說明 返回字串左 右 邊指定個數的新字元 串 該函式有兩個引數。第乙個引數為完整的字串,第二個引數為指定個數。left...