1、概念回溯算法實(shí)際上一個(gè)類(lèi)似枚舉的搜索嘗試過(guò)程,主要是在搜索嘗試過(guò)程中尋找問(wèn)題的解,當(dāng)發(fā)現(xiàn)已不滿足求解條件時(shí),就“回溯”返回,嘗試別的路徑。 回溯法是一種選優(yōu)搜索法,按選優(yōu)條件向前搜索,以達(dá)到目標(biāo)。但當(dāng)探索到某一步時(shí),發(fā)現(xiàn)原先選擇并不優(yōu)或達(dá)不到目標(biāo),就退回一步重新選擇,這種走不通就退回再走的技術(shù)為回溯法,而滿足回溯條件的某個(gè)狀態(tài)的點(diǎn)稱(chēng)為“回溯點(diǎn)”。 許多復(fù)雜的,規(guī)模較大的問(wèn)題都可以使用回溯法,有“通用解題方法”的美稱(chēng)。 2、基本思想在包含問(wèn)題的所有解的解空間樹(shù)中,按照深度優(yōu)先搜索的策略,從根結(jié)點(diǎn)出發(fā)深度探索解空間樹(shù)。當(dāng)探索到某一結(jié)點(diǎn)時(shí),要先判斷該結(jié)點(diǎn)是否包含問(wèn)題的解,如果包含,就從該結(jié)點(diǎn)出發(fā)繼續(xù)探索下去,如果該結(jié)點(diǎn)不包含問(wèn)題的解,則逐層向其祖先結(jié)點(diǎn)回溯。(其實(shí)回溯法就是對(duì)隱式圖的深度優(yōu)先搜索算法)。 若用回溯法求問(wèn)題的所有解時(shí),要回溯到根,且根結(jié)點(diǎn)的所有可行的子樹(shù)都要已被搜索遍才結(jié)束。 而若使用回溯法求任一個(gè)解時(shí),只要搜索到問(wèn)題的一個(gè)解就可以結(jié)束。 3、用回溯法解題的一般步驟:(1)針對(duì)所給問(wèn)題,確定問(wèn)題的解空間: 首先應(yīng)明確定義問(wèn)題的解空間,問(wèn)題的解空間應(yīng)至少包含問(wèn)題的一個(gè)(最優(yōu))解。 (2)確定結(jié)點(diǎn)的擴(kuò)展搜索規(guī)則 (3)以深度優(yōu)先方式搜索解空間,并在搜索過(guò)程中用剪枝函數(shù)避免無(wú)效搜索。 4、算法應(yīng)用示例:八皇后問(wèn)題的遞歸實(shí)現(xiàn)[java] view plaincopy
分書(shū)問(wèn)題: /**
* 回溯法求解分書(shū)問(wèn)題
* @author haolloyin
*/
public class AllacateBooks {
// 書(shū)的總數(shù)量,與總?cè)藬?shù)相等
private int bookCounts = 5;
// like[p][b]=1 表示第 p 個(gè)人喜歡讀第 b 本書(shū)
private int[][] like = new int[bookCounts][bookCounts];
// given[b] = p 表示將第 b 本書(shū)分配給第 p 個(gè)人
private int[] given = new int[bookCounts];
// 初始化標(biāo)識(shí)數(shù)組 given[] 和傳入各人喜歡書(shū)的情況數(shù)組
private void init(int like[][]) {
for (int i = 0; i < bookCounts; i++) {
given[i] = -1; // -1 表示第 i 本書(shū)還沒(méi)分配出去
}
this.like = like;
}
// 嘗試給每一個(gè)人分配一本書(shū)
public void allocateBook(int person) {
for (int bookNum = 0; bookNum < bookCounts; bookNum++) {
if (like[person][bookNum] == 1 && given[bookNum] == -1) {
given[bookNum] = person;
if (person == bookCounts - 1) {
// 打印結(jié)果
for (int i = 0; i < bookCounts; i++) {
System.out.println("人 " + (given[i]+1) + " <---> 書(shū) " + ((char)(i + 'A')));
}
System.out.println();
} else {
// 為下一個(gè)人分配一本書(shū)
allocateBook(person + 1);
}
// 失敗,回溯重新尋找解
given[bookNum] = -1;
}
}
}
// 測(cè)試
public static void main(String[] args) {
// 構(gòu)造一個(gè)問(wèn)題規(guī)模
int[][] like = new int[][]{
{ 0, 0, 1, 1, 0 },
{ 1, 1, 0, 0, 1 },
{ 0, 1, 1, 0, 1 },
{ 0, 0, 0, 1, 0 },
{ 0, 1, 0, 0, 1 }};
AllacateBooks allocateBooks = new AllacateBooks();
allocateBooks.init(like);
allocateBooks.allocateBook(0);
}
}
對(duì)應(yīng)于所給的問(wèn)題規(guī)模,所得的解如下:
人 2 <---> 書(shū) A
人 3 <---> 書(shū) B
人 1 <---> 書(shū) C
人 4 <---> 書(shū) D
人 5 <---> 書(shū) E
人 2 <---> 書(shū) A
人 5 <---> 書(shū) B
人 1 <---> 書(shū) C
人 4 <---> 書(shū) D
人 3 <---> 書(shū) E
[實(shí)驗(yàn)?zāi)康腯 綜合運(yùn)用數(shù)組、遞歸等數(shù)據(jù)結(jié)構(gòu)知識(shí),掌握、提高分析、設(shè)計(jì)、實(shí)現(xiàn)及測(cè)試程序的綜合能力。 [實(shí)驗(yàn)內(nèi)容及要求] 以一個(gè)M×N的長(zhǎng)方陣表示迷宮,0和1分別表示迷宮中的通路和障礙。設(shè)計(jì)一個(gè)程序,對(duì)任意設(shè)定的迷宮,求出一條從入口到出口的通路,或得出沒(méi)有通路的結(jié)論。 (1) 根據(jù)二維數(shù)組,輸出迷宮的圖形。 (2) 探索迷宮的四個(gè)方向:RIGHT為向右,DOWN向下,LEFT向左,UP向上,輸出從入口到出口的行走路徑。 [測(cè)試數(shù)據(jù)] 左上角(1,1)為入口,右下角(8,9)為出口。
[實(shí)現(xiàn)提示] 可使用回溯方法,即從入口出發(fā),順著某一個(gè)方向進(jìn)行探索,若能走通,則繼續(xù)往前進(jìn);否則沿著原路退回,換一個(gè)方向繼續(xù)探索,直至出口位置,求得一條通路。假如所有可能的通路都探索到而未能到達(dá)出口,則所設(shè)定的迷宮沒(méi)有通路。 [java] view plaincopy
|
|
|
來(lái)自: 第一閱覽室 > 《藏經(jīng)閣》