1. 程式人生 > >【資料結構與演算法】backtracking 回溯法

【資料結構與演算法】backtracking 回溯法

backtracking也是一種程式設計思想,使用到了遞迴。

backtracking要解決的問題大致具有這樣的特徵,為了得到問題的解,需要進行若干步驟,每一步的抉擇都是相同的,每一步都是在上一步的基礎上完成的,需要記錄之前的軌跡,直到終點情況,不過有可能是正確也有可能是錯誤。比如最典型的N皇后問題。需要部署N個皇后,每一次部署都有N種可能。

其程式在實現上滿足下列特徵:

(1)每一步的處理,先check特殊情況,即return case;這裡必須有returncase。

(2)再使用一個for迴圈,嘗試每一種選擇,在for迴圈內,先檢測該種選擇是否正確,然後如果正確,就在軌跡上記錄,然後遞迴地處理下一步,處理完以後,再把軌跡恢復,供下一中選擇進行。這裡恢復軌跡是很重要的。

可以分為兩類,一種是尋找全部的解,一種是找到一個解。

一個解:遞迴函式需要返回值,在for迴圈裡面嘗試每一種可能時,如果該選擇返回true,那麼就返回。否則for結束的時候(執行到這裡說明所有嘗試都失敗了)要返回false。利用返回值可以讓程式提前返回,只找到一個解。

多個解:這時遞迴函式可以是void型別,這樣就可以搜全部的解,for迴圈結束也不需要處理。

和dp的比較:這裡是指up到bottom遞迴地dp,二者都涉及了遞迴,但是有差別,dp的遞迴是小規模的遞迴,即解決一個子問題。但是回溯的遞迴是每一步的選擇,可以看成是並列的,都是在一次完整的搜尋中的一步。而且dp是從高到低遞迴,而回溯是從開始到結束,有點從低到高的感覺。

目前為止,涉及到遞迴地思路有分治法,子問題,dp和回溯。很相近,不過還是有差別。

分治法的子問題不重合,子問題是不帶memo的dp,回溯需要記錄軌跡。這些事他們的特徵。

回溯法用於搜尋解,dp找最優解。

下面上一個N皇后的程式碼,回溯的思路體現的很清晰。包括軌跡和恢復。

public List<List<String>> solveNQueens(int n) {
	    List<List<String>> result = new ArrayList<>();
	    char[][] cash = new char[n][n];
	    for(int i = 0; i < n; i++){
	    	for(int j = 0; j < n; j++){
	    		cash[i][j] = '.';
	    	}
	    }
	    solveQ(result, cash, 0, n);
	    return result;
	}

	public void solveQ(List<List<String>> result, char[][] cash, int row, int n){
		if(row == n){
			List<String> r = new ArrayList<>();
			for(int i = 0; i < n; i++){
				String s = "";
				for(int j = 0; j < n; j++){
					s += cash[i][j];
				}
				r.add(s);
			}
			result.add(r);
			return;
		}
		for(int i = 0; i < n; i++){
			if(isright(cash, row, i, n)){
				cash[row][i] = 'Q';
				solveQ(result, cash, row + 1, n);
				cash[row][i] = '.';
			}
		}
	}

	private boolean isright(char[][] cash, int row, int col, int n){
		for(int i = 0; i <= row; i++){
			if(cash[i][col] == 'Q')
				return false;
		}
		int x = row, y = col;
		while(x >= 0 && y >= 0){
			if(cash[x--][y--] == 'Q')
				return false;
		}
		x = row;y = col;
		while(x >= 0 && y < n){
			if(cash[x--][y++] == 'Q')
				return false;
		}
		return true;
	}


相關推薦

資料結構演算法backtracking 回溯

backtracking也是一種程式設計思想,使用到了遞迴。 backtracking要解決的問題大致具有這樣的特徵,為了得到問題的解,需要進行若干步驟,每一步的抉擇都是相同的,每一步都是在上一步的基礎上完成的,需要記錄之前的軌跡,直到終點情況,不過有可能是正確也有可能是錯

資料結構演算法回溯解決裝載問題

回溯法解決裝載問題(約束函式優化) 解題思想 遍歷各元素,若cw+w[t]<=c(即船可以裝下),則進入左子樹,w[t]標記為1,再進行遞迴,若cw+r>bestw(即當前節點的右子樹包含最優解的可能),則進入右子樹,否則,則不遍歷右子樹。 完整程式碼實現如下 p

資料結構演算法回溯解決N皇后問題,java程式碼實現

N皇后問題 問題描述 在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法,這稱為八皇后問題。 延伸一下,便為N皇后問題。 核心思想 解決N皇后問題有兩個關鍵點。一是如何進行放置棋子,二是如何驗證棋子是否符合

資料結構演算法插入排序

 插入排序是演算法中的基礎入門和氣泡排序、選擇排序都是必要掌握的。他們都是對比排序,需要通過比較大小交換位置,進行排序。 插入排序的實現思路: 1、 從第一個元素開始,這個元素可以認為已經被排序。 2、取出下一個元素,在已排序的序列中從後往前掃描。 3、如果該元素小於小於前

資料結構演算法 ---快速排序

快速排序流程: 1.從數列中挑出一個基準值 2.將所有比基準值小的擺放在基準前面,所有比基準值大的擺在後面(相同的數可以放到任一邊);在這個分割槽退出之後,該基準就處於數列的中間位置。 3.遞迴地把“基準值前面的子數列”和“基準值後面的子數列”進行排序。   下面以數列

資料結構演算法------氣泡排序

 學習開發一年的時間裡,很少去了解排序演算法,氣泡排序也是最開始學習的樣子,靠死記硬背,沒有引入自己的理解。  對於什麼時間複雜度和空間複雜度和穩定性也不清楚其原委,或許在程式碼方面少了幾許的天分: 氣泡排序: 氣泡排序每一輪的比較都是前面的數和後面的數進行比較,並交

資料結構演算法之紅黑樹 --- 第十四篇

樹是一種非線性資料結構,這種資料結構要比線性資料結構複雜的多,因此分為三篇部落格進行講解: 第一篇:樹的基本概念及常用操作的Java實現(二叉樹為例) 第二篇:二叉查詢樹 第三篇:紅黑樹 第三篇:紅黑樹 開篇說明:對於紅黑樹的學習,近階段只需要掌握這種資料結構的思想、特點、適

資料結構演算法之二叉查詢樹 --- 第十三篇

樹是一種非線性資料結構,這種資料結構要比線性資料結構複雜的多,因此分為三篇部落格進行講解: 第一篇:樹的基本概念及常用操作的Java實現(二叉樹為例) 第二篇:二叉查詢樹 第三篇:紅黑樹 本文目錄 1、二叉查詢樹的基本概念 2、二叉查詢樹的查詢操作 3、二叉查詢樹的插

資料結構演算法之樹的基本概念及常用操作的Java實現(二叉樹為例) --- 第十二篇

樹是一種非線性資料結構,這種資料結構要比線性資料結構複雜的多,因此分為三篇部落格進行講解: 第一篇:樹的基本概念及常用操作的Java實現(二叉樹為例) 第二篇:二叉查詢樹 第三篇:紅黑樹 本文目錄: 1、基本概念 1.1  什麼是樹 1.2  樹的

資料結構演算法貪心演算法解決揹包問題。java程式碼實現

揹包問題(貪心演算法) 貪心演算法思想 簡單的說,就是將大問題轉化為最優子問題,例如本題所要求的,揹包容量有限,要想使物品的總價值最高,那麼,我們必須儘可能的選擇權重高的(即單位價值更高)的物品進行裝載。 在揹包問題中,物品是可拆的,即可以分成任意部分進行裝載,而最終實現的目標是

資料結構演算法連結串列——遞增排序

今天看書時偶然想到的問題,書上是要求將一個數據插入一個有序連結的線性連結串列中, 所以我想先進行連結串列內的資料排序在進行插入資料。 在這裡我只寫了排序的函式。   函式實現: void Sort(LinkList&list, int &n) {   f

資料結構演算法線性表——刪除重複元素

線性表是一種隨機存取的結構,和連結串列不同,連結串列順序存取的結構。但是,線性表是一種順序儲存的結構,而連結串列是鏈式儲存結構。兩者都是線性的,但區別不同。   進入主題: 1.假如有一串資料元素,要求刪除其中的重複元素。 首先想到的是用兩層迴圈,第一層從第一個元素開始,第

資料結構演算法演算法

一、演算法定義 演算法(algorithm),在數學(算學)和電腦科學之中,為任何良定義的具體計算步驟的一個序列[1],常用於計算、資料處理(英語:Data processing)和自動推理。精確而言,演算法是一個表示為有限長[2]列表的有效方法(英語:Eff

資料結構演算法之複雜度分析---第一篇

一、首先明確兩個問題: 1、為什麼需要對演算法進行復雜度分析? 實際上一個演算法執行所耗費的時間和空間是無法從理論上準確算出來的,必須在計算機上實際執行才知道,但是我們不可能對每個演算法都先在計算機上執行一遍,再決定採用其中效率最高的那個。所以我們就需要從理論上分析出每種

資料結構演算法一、基本

一、絮絮叨叨 計劃寫一系列資料結構與演算法的部落格: 一是給自己立個flag——堅持做完, 二是記錄自己的學習過程,總結和分享知識 1、Why? 面試 =》考查基礎 =》資料結構與演算法 工作 =》有助於理解、使用框架;優化程式,提升效率、效能 鍛鍊邏輯思

資料結構演算法二、陣列

一、線性表 1、定義 線性表(Linear List):零個或多個數據元素的有限序列。 序列(有序):若元素存在多個,則第一個元素無前驅,最後一個無後繼,其他每個元素都有且只有一個前驅和後繼 2、數

資料結構演算法之單鏈表、雙鏈表、迴圈連結串列的基本介紹及其Java程式碼實現---第三篇

一、連結串列的基本介紹 連結串列的定義:連結串列是一種遞迴的資料結構,它或者為空(null),或者是指向一個結點(node)的引用,該結點含有一個泛型的元素和一個指向另一條連結串列的引用。----Algorithms  Fourth  Edition   常見的連結串

資料結構演算法之棧的基本介紹及其陣列、連結串列實現---第四篇

一、棧的基本介紹 1、棧的基本概念 棧是一種限制在一端進行插入和刪除操作的線性表資料結構。棧中有兩個比較重要的操作:push(壓棧:將元素壓入棧頂)和pop(彈棧:從棧頂彈出一個元素)。都滿足先進後出、後進先出的特點! 從圖中可以看出,我們常把棧的上面稱為棧

資料結構演算法之佇列的基本介紹及其陣列、連結串列實現---第五篇

一、佇列的基本概念 1、定義 佇列是一種先進先出的線性表。它只允許在表的前端進行刪除操作,而在表的後端進行插入操作,具有先進先出、後進後出的特點。進行插入操作的一端成為隊尾(tail),進行刪除操作的一端稱為隊頭(head)。當佇列中沒有元素時,則稱之為空佇列。 在

資料結構演算法之遞迴的基本介紹---第六篇

一、遞迴的基本概念 1、定義 遞迴:指的是一個過程,函式直接或者間接的呼叫自己,此時則發生了遞迴。 遞迴的兩個要素:遞推公式和遞迴邊界 可以看到遞迴的定義非常的簡潔,但是理解起來就沒有這麼容易了。不知道大家是否和我一樣,在遇到遞迴問題的時候,總是試圖去一步一步的分