日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【数据结构与算法】【算法思想】回溯算法

發(fā)布時間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据结构与算法】【算法思想】回溯算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

貪心算法
回溯算法
分治算法
動態(tài)規(guī)劃

回溯算法思想應用廣泛,除了用來指導深度優(yōu)先搜索這種經典算法設計之外,還可以用在如正則表達式匹配編譯原理中的語法分析等。

除此之外,很多經典的數學問題都可以用回溯算法解決,比如數獨,八皇后,0-1背包,圖的著色,旅行商問題,全排列等等。

一:如何理解“回溯算法”

回溯的處理思想,有些類似枚舉搜索。枚舉所有的解,找到滿足期望的解。為了有規(guī)律的枚舉所有可能的解,避免遺漏和重復,所以把問題求解的過程分為多個階段。每個階段都有多個選擇,先隨意選擇一個,當發(fā)現(xiàn)走不通時,就退回到上一個岔路口,另選一種走法繼續(xù)走。
常用在“搜索”問題:在一組可能的解中,搜索滿足期望的解

二:例子

八皇后問題

有一個8X8的棋盤,希望往里放8個棋子,每個棋子所在的行,列,對角線都不能有另一個棋子。

第一幅圖滿足要求,第二幅度圖不滿足,八皇后問題就是期望找到所有滿足這種要求的的放棋子的方式。
我們把這個問題劃分成8個階段,依次將8個棋子放到第一行,第二行,第三行……第八行。

int[] result = new int[8];//全局或成員變量,下標表示行,值表示queen存儲在哪一列 public void cal8queens(int row) { // 調用方式:cal8queens(0);if (row == 8) { // 8個棋子都放置好了,打印結果printQueens(result);return; // 8行棋子都放好了,已經沒法再往下遞歸了,所以就return}for (int column = 0; column < 8; ++column) { // 每一行都有8中放法if (isOk(row, column)) { // 有些放法不滿足要求result[row] = column; // 第row行的棋子放到了column列cal8queens(row+1); // 考察下一行}} }private boolean isOk(int row, int column) {//判斷row行column列放置是否合適int leftup = column - 1, rightup = column + 1;for (int i = row-1; i >= 0; --i) { // 逐行往上考察每一行if (result[i] == column) return false; // 第i行的column列有棋子嗎?if (leftup >= 0) { // 考察左上對角線:第i行l(wèi)eftup列有棋子嗎?if (result[i] == leftup) return false;}if (rightup < 8) { // 考察右上對角線:第i行rightup列有棋子嗎?if (result[i] == rightup) return false;}--leftup; ++rightup;}return true; }private void printQueens(int[] result) { // 打印出一個二維矩陣for (int row = 0; row < 8; ++row) {for (int column = 0; column < 8; ++column) {if (result[row] == column) System.out.print("Q ");else System.out.print("* ");}System.out.println();}System.out.println(); }

0-1背包

0-1背包是非常經典的算法問題,很多場景都可以抽象炒年糕這個問題模型。這個問題的經典解法是動態(tài)規(guī)劃,不過還有一種簡單但沒有那么高效的解法,就是回溯算法。
0-1背包問題有很多變體,例如:有一個背包,背包總的承載重量是Wkg。現(xiàn)在有n個物品的重量不等,并且不可分割。我們現(xiàn)在期望選擇幾件物品,裝載到背包中,在不超過所能裝載重量的前提下,如何讓背包中物品的總重量最大?
這個背包問題,在貪心算法中有提到,但在貪心算法中講的物品是可以分割的,可以將物品的一部分裝進背包。此處的背包問題,物品是不可分割的,要么裝要么不裝,所以叫0-1背包問題。
對于每個物品來說,都有兩種選擇,裝進背包或在著不裝進背包。對于n個物品來說,中的裝法就有2^n種,去掉總重量超過過W kg的,從剩下的裝法中選擇中重量最接近W kg的。

可以用回溯的方法,不重復的找到2^n種裝法。把物品依次排列,整個問題就分解為了n個階段,每個階段對應的一個物品怎么選擇。先對第一個物品進行處理,選擇裝進去或是不裝進去,然后在遞歸地處理剩下的物品。

public int maxW = Integer.MIN_VALUE; //存儲背包中物品總重量的最大值 // cw表示當前已經裝進去的物品的重量和;i表示考察到哪個物品了; // w背包重量;items表示每個物品的重量;n表示物品個數 // 假設背包可承受重量100,物品個數10,物品重量存儲在數組a中,那可以這樣調用函數: // f(0, 0, a, 10, 100) public void f(int i, int cw, int[] items, int n, int w) {if (cw == w || i == n) { // cw==w表示裝滿了;i==n表示已經考察完所有的物品if (cw > maxW) maxW = cw;return;}f(i+1, cw, items, n, w);//不選擇當前物品,直接考慮下一個(第 i+1 個),故 cw 不更新if (cw + items[i] <= w) {// 已經超過可以背包承受的重量的時候,就不要再裝了f(i+1,cw + items[i], items, n, w);//表示選擇了當前物品,故考慮下一個時,cw 通過入參更新為 cw + items[i]} }

2 正則表達式

正則表達式里最重要的一種算法思想就是回溯。
正則表達式中,最重要的就是通配符,通配符結合在一起,可以表達非常豐富的語義。假設:正則表達式中只包含 “”和“?”這兩種通配符,并且對這兩種通配符的語義稍微做些改變。其中,“”匹配任意多個(大于等于0個)任意字符,“?”匹配零個或者一個任意字符。基于以上背景假設,看下如何用回溯算法,判斷一個給定的文本,能否跟給定的正則表達式匹配?
依次考察正則表達式中的每個字符,當是非通配符時,就直接跟文本的字符進行匹配,如果相同,則繼續(xù)往下處理;如果不同,則回溯。
如果遇到特殊字符的時候,就有多種處理方式,如“*”有多種匹配方案,可以匹配任意個文本串中的字符,我們就先隨意的選擇一種匹配方案,然后繼續(xù)考察剩下的字符。如果中途發(fā)現(xiàn)無法繼續(xù)匹配下去,就回到這個岔路口,重新選擇一種匹配方案,然后繼續(xù)匹配剩下的字符。

public class Pattern {private boolean matched = false;private char[] pattern; // 正則表達式private int plen; // 正則表達式長度public Pattern(char[] pattern, int plen) {this.pattern = pattern;this.plen = plen;}public boolean match(char[] text, int tlen) { // 文本串及長度matched = false;rmatch(0, 0, text, tlen);return matched;}private void rmatch(int ti, int pj, char[] text, int tlen) {if (matched) return; // 如果已經匹配了,就不要繼續(xù)遞歸了if (pj == plen) { // 正則表達式到結尾了if (ti == tlen) matched = true; // 文本串也到結尾了return;}if (pattern[pj] == '*') { // *匹配任意個字符for (int k = 0; k <= tlen-ti; ++k) {rmatch(ti+k, pj+1, text, tlen);}} else if (pattern[pj] == '?') { // ?匹配0個或者1個字符rmatch(ti, pj+1, text, tlen);rmatch(ti+1, pj+1, text, tlen);} else if (ti < tlen && pattern[pj] == text[ti]) { // 純字符匹配才行rmatch(ti+1, pj+1, text, tlen);}} }

回溯算法本質上就是枚舉,優(yōu)點在于其類似于摸著石頭過河的查找策略,且可以通過剪枝少走冤枉路。它可能適合應用于缺乏規(guī)律,或我們還不了解其規(guī)律的搜索場景中。

筆記整理來源: 王爭 數據結構與算法之美

總結

以上是生活随笔為你收集整理的【数据结构与算法】【算法思想】回溯算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。