演算法學習筆記(二) 01揹包問題之回溯解法

2021-07-10 22:37:55 字數 3214 閱讀 8687

揹包問題,相信各位看官肯定都有所耳聞!筆者就在此簡單的描述一下揹包問題:

給定一揹包和n件物品,揹包的容量為c,第i件物品的重量為w[i],價值為v[i](1<=i<=n);問裝那些物品,可使得價值最大?

思路分析:顯然,每種物品不外乎兩種選擇:裝入和不裝入揹包!若將裝入用狀態1表示,不裝入用狀態0表示;那麼就可構成乙個二叉樹!一共有n層,所以就可通過從第一層開始遍歷搜尋,在裝入的物品總重量不大於c的情況下,找到最優解了!

思路還是蠻簡單的,別的不多說,直接上**:

public

class

demo1

;//每個物體的重量:5個物體

private

staticint

v =;//每個物體的價值

private

staticint

x=newint[6

];//存放每個物體的選中情況

private

static

intbestcp =0

;//當前的最優解

private

staticint

bestcparr

=new

int[6];

private

static

intcount =0

;private

static

intn =5

;//物體的數目

public

static

void

main

(string

args

)system

.out

.println(""

);system

.out

.println

(bestcp

);system

.out

.println

("該樹有"

+count

+"種遍歷方式");}

/***

* @param i:查詢到了第i個物品(i從1開始索引)

* @param cv:當前包中價值

* @param cw:當前包中重量

*/private

static

void

backtrack

(inti ,

intcw

,intcv)

}}else}}

}}

我們知道,回溯法的效率並不是很高的!因為回溯法,就其本質而言,還是屬於窮舉!只不過它就提供了乙個窮舉的思路:回溯!的確也是這樣,上面**中的例子中的物品只由5個,換句話說,所構成的二叉樹也只有5層!但當物品有10個,20個,甚至100個話,構成的二叉樹是多麼的龐大!(筆者覺得不可想象深度為100的二叉樹)!故在上述**的基礎上,很有必要去做乙個演算法的優化!在網上看了別人的部落格之後,大致知道了乙個思路:即在不斷的遍歷左子樹(即不斷的將物品裝入)的過程中,如果出現了不能再裝入下一物品的情況時,這時就需要去遍歷右子樹!但是如果,如果在剩餘容量情況下,將剩餘容量的揹包裝滿(如果大於0且小於物品的重量的話,按照單位重量的價值乘以剩餘容量來算)的情況下 得到的總價值比當前最優解還要的小的話,那麼該右子樹是完全沒有必要去遍歷,而需要直接剪除的!這樣就達到了優化的目的!廢話不多說,直接上**:

/**

*本演算法的上界函式是這樣定義的!首先利用冒泡法排序,按照單位價值右高到低開始順序排列!

*這樣的話,就能保證,先裝進去的是價效比(自己發明的,勿噴)最優的!

而在上界函式中,也是如此,

求的是剩餘

*容量在右子樹所能容納的最**值(揹包容量允許情況下),一旦小於當前最優解,那麼就

*沒有繼續遍歷該右子樹的必要**/

public

class

demo2}}

// 回溯函式

private

static

void

backtrack

(inti)

// 將物品裝進揹包:此種情況的話if(

cw +w[

i]<=c)

if(bound(i

+1)>

bestp

)// 符合條件搜尋右子數

backtrack(i

+1);}

// 計算上界函式

//演算法剩餘容量的情況下最多能裝的價值

private

static

double

bound

(inti)

if(i <=n)

b +=v[

i]/w

[i]*

leftw

;returnb;

}public

static

void

main

(string

args

); //每個物體的重量:5個物體

// private static int v = ; //每個物體的價值v[

0]=0

;v[1

]=6;

v[2]

=3;v

[3]=

5;v[

4]=4

;v[5

]=6;

w[0]

=0;w

[1]=

2;w[

2]=2

;w[3

]=6;

w[4]

=5;w

[5]=

5;n =

5;c =

10;knapsack

();backtrack(1

);system

.out

.println

(bestp

);for

(inti =

1;i <=n;

i++)

system

.out

.println(""

);}}

現在,我們來分析下時間複雜度,最好的情況當然是能夠剪除所有的右子樹,而最優的物品選擇剛好全在左子樹上了!而最壞的情況自然是搜尋右子樹的次數最多了呀!

到此,直接遍歷窮舉和優化之後的回溯法來解決10揹包問題的分析解答終於寫完了!寫了一上午啊!

筆者水平有限,望各位看官勿怪!

參考部落格:

優化的回溯法解決10揹包問題

遍歷的回溯法解決10揹包問題

演算法學習 01揹包問題

是慕課網的實戰演算法課程 動態規劃 相當於還是求n個物品的組合!暴力解法 每一件物品,都可以放進揹包,也可以不放進。複雜度是o 2 n n 對於每乙個組合,還要看看對應的總重是多少,看看是不是超過了容量c,從而看價值。組合方式都可以用遞迴的方式來求解。只是是能不能找到重疊子問題 最優子結構,從而轉換...

演算法學習筆記之基礎dp之(0 1)揹包問題

揹包問題 有多個物品,重量不同 價值不同,以及乙個容量有限的揹包,選擇一些物品撞到揹包中,問怎麼裝才能使裝進揹包的物品總價值最大。根據不同的的限定條件,可以報揹包問題分為很多種,常見的有下面兩種 如果每個物品可以切分,稱為一般揹包問題,用貪心法求最優解。比如吃自助餐,在飯量一定的情況下,怎麼吃才能使...

揹包問題之0 1揹包 二

問題描述 有n個物品,第i個物品的重量為w i 價值為v i 選一些物品放入揹包中,使揹包內物品總重量恰好為w的前提下,總價值盡量大。輸入 有多組測試資料,每組資料第一行為2個正整數,分別代表物品的個數n和揹包的容量w,接下來的n行,每行2個正整數,用空格隔開,分別代表物品的重量w和價值v,當n w...