主頁 > 軟體設計 > 回溯演算法----來自“0-1背包“問題的闡述

回溯演算法----來自“0-1背包“問題的闡述

2021-09-22 10:48:14 軟體設計

回溯演算法

“不進則退,不喜則憂,不得則亡,此世人之常,”----《鄧析子·無后篇》

文章目錄

    • 回溯演算法
  • 前言
  • 一、回溯和回溯演算法
    • (1)何為"回溯"?
    • (2) 何為"回溯演算法"?
  • 二、實體展現----0-1背包問題
    • (1)問題簡述
    • (2) 問題分析
    • (3) 演算法設計
    • (4) 模擬程序
    • (5) 代碼實作
    • 總結
    • 致謝


前言

回溯法被稱為萬能解法,更內涵退一步海闊天空的人生哲理,


一、回溯和回溯演算法

(1)何為"回溯"?

遺失的美好,你想在重復中找回當時的心動,沿著軌跡回溯,路過的風景卻全都已經不是當年的意味,世界上只剩下兩種人:像她的和不像她的,

(2) 何為"回溯演算法"?

回溯法是一種選優搜索法,按照選優條件深度優先搜索,直至達成目標,當搜索到某一步時,發現原先選擇并不是最優或無法達到目標,就退回一步重新選擇,這種走不通就退回再走的技術稱為回溯法,而滿足回溯條件的某個狀態稱為“回溯點”,

二、實體展現----0-1背包問題

(1)問題簡述

0-1背包問題:提供一個容量(也可以看作是載重量)是W的購物車和n件物品,每個物品 i 對應的價值為Vi,重量為Wi,每個物品只有一件,要么裝入要么不裝入,不可拆分,如何選擇物品,使裝入購物車的價值最高,

(2) 問題分析

從n件物品中選擇一些物品,相當于從n個物品組成的集合S中找到一個子集,該子集的所有物品的總重量不得超過購物車的容量,并且這些物品在滿足條件的情況下總價值最大,

(3) 演算法設計

1. 定義問題的解空間

對于每個物品,都只有兩種結果,裝入和不裝入,但是該物品是否裝入為未知,所以為方便期間,可以定義變數 Xi 來表示第 i 個物品是否裝入,如果裝入則使 Xi 的值為1,否則為0,該問題解的形式是一個n元組,且每個分量的取值為 0 或 1.由此可知,問題的解空間為{ X1 ,X2 ,X3,······ ,Xn },其中Xi為0 或 1,i 為1,2,3,4,······ ,n,

2. 確定解空間的組織結構

不難看出該問題的解是 n 個元素組成的集合所有子集個數,
例如 n 的值為3(即物品共有3個),那么解空間是{ 0, 0,0 } , { 0 ,0 ,1 }, { 0 , 1, 1 }, { 1 ,1,1 }, { 0 ,1 ,0 }, { 1 ,0 ,0 }, {1 ,0 ,1 },{ 1 ,1 ,0 },
可見問題的解空間樹的深度為問題的規模 n (也就是物品的總數量),
兄弟們點贊再走,畫圖是真的累

3. 搜索解空間

約束條件:

可容易看出 ∑Wi Xi<=W (下界是i=1,上界是n)

限界條件

根據解空間的組織結構,對于任意一個中間結點z,從根節點到z結點的分支所代表的狀態(是否裝入購物車)已經確定,從z到其子孫結點的分支狀態不確定,也就是說,如果z在解空間樹中處于第t層,說明第一種物品到第t-1 種物品的狀態已經確定,我們只需要沿著z的分支擴展確定第t種物品的狀態即可,為方便起見,我們用 CP 表示已經裝入購物車的物品的總價值,切記,已裝入的價值高并不一定是最優的,因為還有其他情況未確定,
由于我們未確定第t+1種物品到第 n 種物品的實際情況,所以只能估計他們的情況,假設第t+1種物品到第n種物品都裝入購物車,第t+1種物品到第n種物品的總價值用 rp 表示,因此 CP+rp是所有從根出發經過中間結點z的可行解的價值上界,
一鍵三聯,拜托
如果價值上界小于或等于當前搜索到的最優值(最優值用bestp表示,初始值為0),則無繼續搜索的必要,反之,則繼續搜索,
限界條件為: CP+rp>bestp

搜索程序

從根節點開始,深度優先式的搜索,根節點首先成為活結點,也是當前拓展結點,定義左分支為1,即左子樹表示該物品放入購物車,右分支為0,表示不放入購物車,起始沿著左分支進行拓展,往后需要判斷是否滿足限定條件,如果滿足則繼續沿著左分支拓展,否則沿著右分支拓展,如果不滿足則回溯到最近的父親結點繼續拓展其他情況,直到所有情況都被考慮到,

(4) 模擬程序

假設現在有4個物品和一個購物車,每個物品的重量w為(2,5,4,2),價值為(6,3,5,4),購物車重量W是10.
1.初始化

sumw和sumv分別用來統計所有物品的總重量和總價值,sumw=13,sumv=18,sumw>W,因此不能全部裝完,需要擇優選取,當前放入購物車的重量是cw=0,當前放入購物車的價值為cp=0,當前最優值bestp=0.

2.搜索第一層

擴展 1 號結點,首先判斷cw+w[1]=2<W,滿足約束條件,擴展左分支,令X[1]=1,cw=cw+w[1]=2,cp=cp+v[1]=6,生成二號節點,
求三聯
求三聯

3.擴展2號結點

首先判斷cw+w[2]=7<W,滿足約束條件,擴展左分支,令x[2]=1,cw=cw+w[2]=7,cp=cp+v[2]=9,生成三號節點,

求三聯

4. 擴展3號結點

首先判斷cw+w[3]=11>W,超過了購物車容量,第三個物品不能放入,那么判斷bound(t+1)是否大于bestp,bound(4)中剩余物品只有第四個,rp=4,cp+rp=13,bestp=0,因此滿足限界條件,擴展右子樹,令x[3]=0,生成四號結點,
求三聯

5. 擴展4號結點

首先判斷cw+w[4]=9<W,滿足約束條件,擴展左分支,令x[4]=1,cw=cw+w[4]=9,cp=cp+v[4]=13,生成5號結點,
求三聯

6. 擴展5號結點

t>n,找到當前一個最優解,用bestx[ ]保存當前最優解{ 1 ,1 ,0, 1 },保存當前最優值bestp=13,5號結點成為死點,

7. 回溯到4號結點,一直向上回溯到2號結點,

向上回溯到4號結點,回溯時cw=cw-w[4]=7,cp=cp-v[4]=9.如何加上的,如何減去,4號結點右子樹還未生成,考察bound(t+1)是否大于bestp,判斷可知不滿足條件,故不在擴展4號結點的右分支,4號結點為死點,向上繼續回溯至3號結點,3號結點左右孩子都已經考察過,為死點,繼續回溯至2號結點,回溯時cw=cw-w[2]=2,cp=cp-v[2]=6.
求三聯

8. 擴展2號結點

2號結點右子樹還未生成,考察bound(t+1)是否大于bestp,bound(3)中剩余物品為第3、4個物品,rp=9,cp+rp=15>bestp=13,滿足條件,擴展右子樹,令x[2]=0,生成6號結點,
求三聯

9. 擴展6號結點

首先判斷cw+w[3]=6<W,滿足約束條件,擴展左分支,令x[3]=1,cw=cw+w[3]=6,cp=cp+v[3]=11,生成7號結點,
求三聯

10. 擴展7號結點

首先判斷cw+w[4]=8<W,滿足約束條件,擴展左分支,令x[4]=1,cw=cw+w[4]=8,cp=cp+v[4]=15,生成8號結點,
求三聯

11. 擴展8號結點

t>n,找到一個最優解,用bestx[ ]保存最優解{ 1 , 0 ,1 ,1 },保存最優值bestp=10,8號為死點,回溯至7號結點,cw=cw-w[4]=6,cp=cp-v[4]=11.

12. 擴展7號結點

7號右子樹還未生成,考察發現不滿足限界條件,不再擴展,向上回溯至6號結點,cw=cw-w[3]=2,cp=cp-v[3]=6.

13. 擴展6號結點

6號結點右子樹未生成,判斷發現不滿足限界條件,向上回溯至2號結點,cw=cw-w[1]=0,cp=cp-v[1]=0.

14. 擴展1號結點

1號結點右分支未生成,判斷發現不滿足限界條件,演算法結束,
求三聯

(5) 代碼實作

C++代碼

double Bound(int i) //計算上界
{
    int rp=0; //剩余物品為第i到n種物品,
    while(i<=n) //依次計算剩余物品的價值
    {
    rp+=v[i];
    i++;
    }
    return cp+rp; //回傳上界
}

void Backtrack(int t) //t表示當前擴展結點在第t層
{
    if(t>n)
    {
        for(j=1;j<=n;j++)
        {
            bestx[j]=x[j];
        }
        bestrp=cp;
        return ;
    }
    if(cw+w[t]<=W)
    {
        x[t]=1;
        cw+=w[t];
        cp+=v[t];
        Backtrack(t+1);
        cw-=w[t];
        cp-=v[t];
    }
    if(Bound(t+1)>bestp)
    {
        x[t]=0;
        Backtrack(t+1);
    }
}

Python代碼

def backtrack(i):#global是可以讓函式處理函式外的變數
    global bestV, curW, curV, x, bestx
    if i >= n:
        if bestV < curV:
            bestV = curV
            bestx = x[:]
    else:
        if curW + w[i] <= c:
            x[i] = True
            curW += w[i]
            curV += v[i]
            backtrack(i + 1)
            curW -= w[i]
            curV -= v[i]
        x[i] = False
        backtrack(i + 1)


if __name__ == '__main__':
    n = 5
    c = 10
    w = [2, 2, 6, 5, 4]
    v = [6, 3, 5, 4, 6]
    x = [False for i in range(n)]
    backtrack(0)
    print(bestV)
    print(bestx)

Java代碼:參考自CSDN博主:落雪侵越,文章鏈接:落雪侵越

/**
 * 回溯
 * @param t
 */
public static void BackTrack(int t) {
    if(t>count) {//到達葉結點
        if(cp>bestp) {
            for(int i = 1;i<=count;i++) {
                bestx[i] = cx[i];
            }

            bestp = cp;
        }
        return;
    }

    r -= p[t];
    if(cw + w[t] <= c) {//搜索左子樹
        cx[t] = 1;
        cp += p[t];
        cw += w[t];
        BackTrack(t+1);
        cp -= p[t];//恢復現場
        cw -= w[t];//恢復現場

    }

    if(cp + r >bestp) {//剪枝操作
        cx[t] = 0;//搜索右子樹
        BackTrack(t+1);
    }
    r += p[t];//恢復現場
}

C語言:轉自CSDN博主:永遠的9,文章地址:永遠的9

#include<stdio.h>
#define max 100
 
int weight[max];
int value[max];
int n,max_weight,max_value;
 
int best_answer[max],answer[max];
 
void print()
{
	int i,j,k,l;
	printf("+++++++++++++%d++++++++++++\n",max_value);
	
	for(i=1;i<=n;i++)
		printf("%d ",best_answer[i]);
	printf("\n");
}
 
void DFS(int level,int current_weight,int current_value)
{
	if(level>=n+1)
	{
		if(current_value>max_value)
		{
			int i;
			max_value = current_value;
			for(i=1;i<=n;i++)
				best_answer[i] = answer[i];
		}
	}
	else
	{
		if(current_weight>=weight[level+1])
		{
			current_weight = current_weight - weight[level+1];
			current_value = current_value + value[level+1];
			answer[level+1] = 1;
			DFS(level+1,current_weight,current_value);
			answer[level+1] = 0;
			current_weight = current_weight + weight[level+1];
			current_value = current_value - value[level+1];
		}
		DFS(level+1,current_weight,current_value);
	}
}
 
void init()
{
	int i,j,k,l;
	max_value = 0;
	for(i=1;i<=n;i++)
		answer[i] = 0;
}
 
int main()
{
	int i,j,k,l;
	while(scanf("%d%d",&n,&max_weight)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%d",&weight[i]);
		for(j=1;j<=n;j++)
			scanf("%d",&value[j]);
		
		init();
		
		DFS(0,max_weight,0);
		
		print();
			
		
	}
	return 0;
	
}

總結

回溯演算法本質是一種暴力演算法,畢竟在絕對實力的面前,一切花里胡哨都如螻蟻,本人才疏學淺,出錯在所難免,還望各位不吝賜教,多加指正,鄙人先行謝過,最后,送大家一句話:風可以吹滅蠟燭,卻能使火越燒越旺!

致謝

感謝CSDN博客專家、2020年博客之星TOP5、藍橋杯簽約作者1_bit對本 人Python和演算法學習的建議;
感謝南陽理工學院陳小玉教授的網路遠程指導;
感謝滴滴出行的劉景亮學長對本人C++的指導以及資料結構與演算法的寶貴建議和資源的分享;
感謝致易王俊學長對本人Python演算法實作的除錯、建議與幫助;
感謝知某、某Code、某Time上各網友的建議和資源分享,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/302007.html

標籤:其他

上一篇:C | 整型資料在記憶體中存盤形式和大小端存盤

下一篇:阿達的紅外射頻遙控盒子

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more