當前位置:首頁 » 編程語言 » 背包問題動態規劃python

背包問題動態規劃python

發布時間: 2024-07-14 08:10:45

㈠ 鍔ㄦ佽勫垝奼傝В0-1鑳屽寘闂棰

闅鵑亾鏄鎯寵佺▼搴忥紵

F[I,j]涓哄墠i涓鐗╁搧涓閫夋嫨鑻ュ共涓鏀懼叆浣垮叾浣撶Н姝eソ涓簀鐨勬爣蹇楋紝涓哄竷灝斿瀷銆
瀹炵幇:灝嗘渶浼樺寲闂棰樿漿鍖栦負鍒ゅ畾鎬ч棶棰
f [I, j] = f [ i-1, j-w[i] ] (w[I]<=j<=v) 杈圭晫錛歠[0,0]:=true.
For I:=1 to n do
For j:=w[I] to v do F[I,j]:=f[I-1,j-w[I]];
浼樺寲錛氬綋鍓嶇姸鎬佸彧涓庡墠涓闃舵電姸鎬佹湁鍏籌紝鍙闄嶈嚦涓緇淬
F[0]:=true;
For I:=1 to n do begin
F1:=f;
For j:=w[I] to v do
If f[j-w[I]] then f1[j]:=true;
F:=f1;
End;

B.奼傚彲浠ユ斁鍏ョ殑鏈澶т環鍊箋
F[I,j] 涓哄歸噺涓篒鏃跺彇鍓峧涓鑳屽寘鎵鑳借幏寰楃殑鏈澶т環鍊箋
F [i,j] = max { f [ i 鈥 w [ j ], j-1] + p [ j ], f[ i,j-1] }

C.奼傛伆濂借呮弧鐨勬儏鍐墊暟銆
DP:
Procere update;
var j,k:integer;
begin
c:=a;
for j:=0 to n do
if a[j]>0 then
if j+now<=n then inc(c[j+now],a[j]);
a:=c;
end;

鍦0 / 1鑳屽寘闂棰樹腑錛岄渶瀵瑰歸噺涓篶 鐨勮儗鍖呰繘琛岃呰澆銆備粠n 涓鐗╁搧涓閫夊彇瑁呭叆鑳屽寘鐨勭墿鍝侊紝姣忎歡鐗╁搧i 鐨勯噸閲忎負wi 錛屼環鍊間負pi 銆傚逛簬鍙琛岀殑鑳屽寘瑁呰澆錛岃儗鍖呬腑鐗╁搧鐨勬婚噸閲忎笉鑳借秴榪囪儗鍖呯殑瀹歸噺錛屾渶浣寵呰澆鏄鎸囨墍瑁呭叆鐨勭墿鍝佷環鍊兼渶楂橈紝鍗硃1*x1+p2*x1+...+pi*xi(鍏1<=i<=n錛寈鍙0鎴1錛屽彇1琛ㄧず閫夊彇鐗╁搧i) 鍙栧緱鏈澶у箋
鍦ㄨラ棶棰樹腑闇瑕佸喅瀹歺1 .. xn鐨勫箋傚亣璁炬寜i = 1錛2錛...錛宯 鐨勬″簭鏉ョ『瀹歺i 鐨勫箋傚傛灉緗畑1 = 0錛屽垯闂棰樿漿鍙樹負鐩稿逛簬鍏朵綑鐗╁搧(鍗崇墿鍝2錛3錛.錛宯)錛岃儗鍖呭歸噺浠嶄負c 鐨勮儗鍖呴棶棰樸傝嫢緗畑1 = 1錛岄棶棰樺氨鍙樹負鍏充簬鏈澶ц儗鍖呭歸噺涓篶-w1 鐨勯棶棰樸傜幇璁緍?{c錛宑-w1 } 涓哄墿浣欑殑鑳屽寘瀹歸噺銆
鍦ㄧ涓嬈″喅絳栦箣鍚庯紝鍓╀笅鐨勯棶棰樹究鏄鑰冭檻鑳屽寘瀹歸噺涓簉 鏃剁殑鍐崇瓥銆備笉綆x1 鏄0鎴栨槸1錛孾x2 錛.錛寈n ] 蹇呴』鏄絎涓嬈″喅絳栦箣鍚庣殑涓涓鏈浼樻柟妗堬紝濡傛灉涓嶆槸錛屽垯浼氭湁涓涓鏇村ソ鐨勬柟妗圼y2錛.錛寉n ]錛屽洜鑰孾x1錛寉2錛.錛寉n ]鏄涓涓鏇村ソ鐨勬柟妗堛
鍋囪緉=3, w=[100,14,10], p=[20,18,15], c= 116銆傝嫢璁緓1 = 1錛屽垯鍦ㄦ湰嬈″喅絳栦箣鍚庯紝鍙鐢ㄧ殑鑳屽寘瀹歸噺涓簉= 116-100=16 銆俒x2錛寈3 ]=[0,1] 絎﹀悎瀹歸噺闄愬埗鐨勬潯浠訛紝鎵寰楀間負1 5錛屼絾鍥犱負[x2錛寈3 ]= [1錛0] 鍚屾牱絎﹀悎瀹歸噺鏉′歡涓旀墍寰楀間負1 8錛屽洜姝[x2錛寈3 ] = [ 0錛1] 騫墮潪鏈浼樼瓥鐣ャ傚嵆x= [ 1錛0錛1] 鍙鏀硅繘涓簒= [ 1錛1錛0 ]銆傝嫢璁緓1 = 0錛屽垯瀵逛簬鍓╀笅鐨勪袱縐嶇墿鍝佽岃█錛屽歸噺闄愬埗鏉′歡涓116銆傛諱箣錛屽傛灉瀛愰棶棰樼殑緇撴灉[x2錛寈3 ]涓嶆槸鍓╀綑鎯呭喌涓嬬殑涓涓鏈浼樿В錛屽垯[x1錛寈2錛寈3 ]涔熶笉浼氭槸鎬諱綋鐨勬渶浼樿В銆傚湪姝ら棶棰樹腑錛屾渶浼樺喅絳栧簭鍒楃敱鏈浼樺喅絳栧瓙搴忓垪緇勬垚銆傚亣璁緁 (i,y) 琛ㄧず鍓╀綑瀹歸噺涓簓錛屽墿浣欑墿鍝佷負i錛宨 + 1錛...錛宯 鏃剁殑鏈浼樿В鐨勫礆紝鍗籌細鍒╃敤鏈浼樺簭鍒楃敱鏈浼樺瓙搴忓垪鏋勬垚鐨勭粨璁猴紝鍙寰楀埌f 鐨勯掑綊寮忎負錛
褰搄>=wi鏃訛細 f(i,j)=max{f(i+1,j),f(i+1,j-wi)+vi} 鈶犲紡
褰0<=j<wi鏃訛細f(i,j)=f(i+1,j) 鈶″紡
fn( 1 ,c) 鏄鍒濆嬫椂鑳屽寘闂棰樼殑鏈浼樿В銆
浠ユ湰棰樹負渚嬶細鑻0鈮y錛1 0錛屽垯f ( 3 ,y) = 0錛涜嫢y鈮1 0錛宖 ( 3 ,y) = 1 5銆傚埄鐢ㄢ憽寮忥紝鍙寰梖 (2, y) = 0 ( 0鈮y錛10 )錛沠(2錛寉)= 1 5(1 0鈮y錛1 4)錛沠(2錛寉)= 1 8(1 4鈮y錛2 4)鍜宖(2錛寉)= 3 3(y鈮2 4)銆傚洜姝ゆ渶浼樿Вf ( 1 , 11 6 ) = m a x {f(2錛11 6)錛宖(2錛11 6 - w1)+ p1} = m a x {f(2錛11 6)錛宖(2錛1 6)+ 2 0 } = m a x { 3 3錛3 8 } = 3 8銆
鐜板湪璁$畻xi 鍊礆紝姝ラゅ備笅錛氳嫢f ( 1 ,c) =f ( 2 ,c)錛屽垯x1 = 0錛屽惁鍒檟1 = 1銆傛帴涓嬫潵闇浠庡墿浣欏歸噺c-w1涓瀵繪眰鏈浼樿В錛岀敤f (2, c-w1) 琛ㄧず鏈浼樿В銆備緷姝ょ被鎺錛屽彲寰楀埌鎵鏈夌殑xi (i= 1.n) 鍊箋
鍦ㄨヤ緥涓錛屽彲寰楀嚭f ( 2 , 116 ) = 3 3鈮爁 ( 1 , 11 6 )錛屾墍浠x1 = 1銆傛帴鐫鍒╃敤榪斿洖鍊3 8 -p1=18 璁$畻x2 鍙妜3錛屾ゆ椂r = 11 6 -w1 = 1 6錛屽張鐢眆 ( 2 , 1 6 ) = 1 8錛屽緱f ( 3 , 1 6 ) = 1 4鈮爁 ( 2 , 1 6 )錛屽洜姝x2 = 1錛屾ゆ椂r= 1 6 -w2 = 2錛屾墍浠f (3,2) =0錛屽嵆寰梮3 = 0銆

㈡ 01背包問題

演算法分析

對於背包問題,通常的處理方法是搜索。
用遞歸來完成搜索,演算法設計如下:
function Make( i {處理到第i件物品} , j{剩餘的空間為j}:integer) :integer;
初始時i=m , j=背包總容量
begin
if i:=0 then
Make:=0;
if j>=wi then (背包剩餘空間可以放下物品 i )
r1:=Make(i-1,j-wi)+v; (第i件物品放入所能得到的價值 )
r2:=Make(i-1,j)(第i件物品不放所能得到的價值 )
Make:=max{r1,r2}
end;
這個演算法的時間復雜度是O(2^n),我們可以做一些簡單的優化。
由於本題中的所有物品的體積均為整數,經過幾次的選擇後背包的剩餘空間可能會相等,在搜索中會重復計算這些結點,所以,如果我們把搜索過程中計算過的結點的值記錄下來,以保證不重復計算的話,速度就會提高很多。這是簡單?quot;以空間換時間"。
我們發現,由於這些計算過程中會出現重疊的結點,符合動態規劃中子問題重疊的性質。
同時,可以看出如果通過第N次選擇得到的是一個最優解的話,那麼第N-1次選擇的結果一定也是一個最優解。這符合動態規劃中最優子問題的性質。
考慮用動態規劃的方法來解決,這里的:
階段是:在前N件物品中,選取若干件物品放入背包中;
狀態是:在前N件物品中,選取若干件物品放入所剩空間為W的背包中的所能獲得的最大價值;
決策是:第N件物品放或者不放;
由此可以寫出動態轉移方程:
我們用f[i,j]表示在前 i 件物品中選擇若干件放在所剩空間為 j 的背包里所能獲得的最大價值
f[i,j]=max{f[i-1,j-Wi]+Pi (j>=Wi), f[i-1,j]}
這個方程非常重要,基本上所有跟背包相關的問題的方程都是由它衍生出來的。所以有必要將它詳細解釋一下:「將前i件物品放入容量為v的背包中」這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為一個只牽扯前i-1件物品的問題。如果不放第i件物品,那麼問題就轉化為「前i-1件物品放入容量為v的背包中」,價值為f[v];如果放第i件物品,那麼問題就轉化為「前i-1件物品放入剩下的容量為v-c的背包中」,此時能獲得的最大價值就是f[v-c]再加上通過放入第i件物品獲得的價值w。
這樣,我們可以自底向上地得出在前M件物品中取出若干件放進背包能獲得的最大價值,也就是f[m,w]
演算法設計如下:
procere Make;
begin
for i:=0 to w do
f[0,i]:=0;
for i:=1 to m do
for j:=0 to w do begin
f[i,j]:=f[i-1,j];
if (j>=w) and (f[i-1,j-w]+v>f[i,j]) then
f[i,j]:=f[i-1,j-w]+v;
end;
writeln(f[m,wt]);
end;
由於是用了一個二重循環,這個演算法的時間復雜度是O(n*w)。而用搜索的時候,當出現最壞的情況,也就是所有的結點都沒有重疊,那麼它的時間復雜度是O(2^n)。看上去前者要快很多。但是,可以發現在搜索中計算過的結點在動態規劃中也全都要計算,而且這里算得更多(有一些在最後沒有派上用場的結點我們也必須計算),在這一點上好像是矛盾的。
事實上,由於我們定下的前提是:所有的結點都沒有重疊。也就是說,任意N件物品的重量相加都不能相等,而所有物品的重量又都是整數,那末這個時候W的最小值是:1+2+2^2+2^3+……+2^n-1=2^n -1
此時n*w>2^n,動態規劃比搜索還要慢~~|||||||所以,其實背包的總容量W和重疊的結點的個數是有關的。
考慮能不能不計算那些多餘的結點……
優化時間復雜度
以上方法的時間和空間復雜度均為O(N*V),其中時間復雜度基本已經不能再優化了,但空間復雜度卻可以優化到O(V)。
先考慮上面講的基本思路如何實現,肯定是有一個主循環i=1..N,每次算出來二維數組f[0..V]的所有值。那麼,如果只用一個數組f[0..V],能不能保證第i次循環結束後f[v]中表示的就是我們定義的狀態f[v]呢?f[v]是由f[v]和f[v-c]兩個子問題遞推而來,能否保證在推f[v]時(也即在第i次主循環中推f[v]時)能夠得到f[v]和f[v-c]的值呢?事實上,這要求在每次主循環中我們以v=V..0的順序推f[v],這樣才能保證推f[v]時f[v-c]保存的是狀態f[v-c]的值。偽代碼如下:
for i=1..N
for v=V..0
f[v]=max{f[v],f[v-c]+w};
其中的f[v]=max{f[v],f[v-c]}一句恰就相當於我們的轉移方程f[v]=max{f[v],f[v-c]},因為現在的f[v-c]就相當於原來的f[v-c]。如果將v的循環順序從上面的逆序改成順序的話,那麼則成了f[v]由f[v-c]推知,與本題意不符,但它卻是另一個重要的背包問題P02最簡捷的解決方案,故學習只用一維數組解01背包問題是十分必要的。
事實上,使用一維數組解01背包的程序在後面會被多次用到,所以這里抽象出一個處理一件01背包中的物品過程,以後的代碼中直接調用不加說明。
過程ZeroOnePack,表示處理一件01背包中的物品,兩個參數cost、weight分別表明這件物品的費用和價值。
procere ZeroOnePack(cost,weight)
for v=V..cost
f[v]=max{f[v],f[v-cost]+weight}
注意這個過程里的處理與前面給出的偽代碼有所不同。前面的示常式序寫成v=V..0是為了在程序中體現每個狀態都按照方程求解了,避免不必要的思維復雜度。而這里既然已經抽象成看作黑箱的過程了,就可以加入優化。費用為cost的物品不會影響狀態f[0..cost-1],這是顯然的。
有了這個過程以後,01背包問題的偽代碼就可以這樣寫:
for i=1..N
ZeroOnePack(c,w);
初始化的細節問題

我們看到的求最優解的背包問題題目中,事實上有兩種不太相同的問法。有的題目要求「恰好裝滿背包」時的最優解,有的題目則並沒有要求必須把背包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。
如果是第一種問法,要求恰好裝滿背包,那麼在初始化時除了f[0]為0其它f[1..V]均設為-∞,這樣就可以保證最終得到的f[N]是一種恰好裝滿背包的最優解。
如果並沒有要求必須把背包裝滿,而是只希望價格盡量大,初始化時應該將f[0..V]全部設為0。
為什麼呢?可以這樣理解:初始化的f數組事實上就是在沒有任何物品可以放入背包時的合法狀態。如果要求背包恰好裝滿,那麼此時只有容量為0的背包可能被價值為0的nothing「恰好裝滿」,其它容量的背包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果背包並非必須被裝滿,那麼任何容量的背包都有一個合法解「什麼都不裝」,這個解的價值為0,所以初始時狀態的值也就全部為0了。
這個小技巧完全可以推廣到其它類型的背包問題,後面也就不再對進行狀態轉移之前的初始化進行講解

㈢ 用動態規劃演算法怎樣求解01背包問題

動態規劃主要解決的是多階段的決策問題。

01背包中,狀態為背包剩餘的容量,階段是每一個物品,決策是是否選擇當前的物品。


所以用動態規劃來解決是非常貼切的。

我們設f[V]表示已經使用容量為V時所能獲得的最大價值,w[i]表示i物品的質量,c[i]表示i物品的價值。

for(inti=1;i<=n;i++)
for(intj=V;j>=w[i];j--)
f[j]=max(f[j],f[j-w[i]]+c[i]);

這便是所謂的一個狀態轉移方程。

f[j]表示在已經使用容量為j時的最大價值,f[j-w[i]]表示在已經使用容量為j-w[i]時的最大價值。

f[j]可以由f[j-w[i]]這個狀態轉移到達,表示選取w[i]這個物品,並從而獲得價值為c[i]。

而每次f[j]會在選與不選中決策選出最優的方案。

從每一個物品,也就是每一個階段的局部最優推出最後的全局最優值。這樣就解決了01背包問題

㈣ 0-1背包問題的多種解法代碼(動態規劃、貪心法、回溯法、分支限界法)

一.動態規劃求解0-1背包問題
/************************************************************************/
/* 0-1背包問題:
/* 給定n種物品和一個背包
/* 物品i的重量為wi,其價值為vi
/* 背包的容量為c
/* 應如何選擇裝入背包的物品,使得裝入背包中的物品
/* 的總價值最大?
/* 註:在選擇裝入背包的物品時,對物品i只有兩種選擇,
/* 即裝入或不裝入背包。不能將物品i裝入多次,也
/* 不能只裝入部分的物品i。
/*
/* 1. 0-1背包問題的形式化描述:
/* 給定c>0, wi>0, vi>0, 0<=i<=n,要求找到一個n元的
/* 0-1向量(x1, x2, ..., xn), 使得:
/* max sum_{i=1 to n} (vi*xi),且滿足如下約束:
/* (1) sum_{i=1 to n} (wi*xi) <= c
/* (2) xi∈{0, 1}, 1<=i<=n
/*
/* 2. 0-1背包問題的求解
/* 0-1背包問題具有最優子結構性質和子問題重疊性質,適於
/* 採用動態規劃方法求解
/*
/* 2.1 最優子結構性質
/* 設(y1,y2,...,yn)是給定0-1背包問題的一個最優解,則必有
/* 結論,(y2,y3,...,yn)是如下子問題的一個最優解:
/* max sum_{i=2 to n} (vi*xi)
/* (1) sum_{i=2 to n} (wi*xi) <= c - w1*y1
/* (2) xi∈{0, 1}, 2<=i<=n
/* 因為如若不然,則該子問題存在一個最優解(z2,z3,...,zn),
/* 而(y2,y3,...,yn)不是其最優解。那麼有:
/* sum_{i=2 to n} (vi*zi) > sum_{i=2 to n} (vi*yi)
/* 且,w1*y1 + sum_{i=2 to n} (wi*zi) <= c
/* 進一步有:
/* v1*y1 + sum_{i=2 to n} (vi*zi) > sum_{i=1 to n} (vi*yi)
/* w1*y1 + sum_{i=2 to n} (wi*zi) <= c
/* 這說明:(y1,z2,z3,...zn)是所給0-1背包問題的更優解,那麼
/* 說明(y1,y2,...,yn)不是問題的最優解,與前提矛盾,所以最優
/* 子結構性質成立。
/*
/* 2.2 子問題重疊性質
/* 設所給0-1背包問題的子問題 P(i,j)為:
/* max sum_{k=i to n} (vk*xk)
/* (1) sum_{k=i to n} (wk*xk) <= j
/* (2) xk∈{0, 1}, i<=k<=n
/* 問題P(i,j)是背包容量為j、可選物品為i,i+1,...,n時的子問題
/* 設m(i,j)是子問題P(i,j)的最優值,即最大總價值。則根據最優
/* 子結構性質,可以建立m(i,j)的遞歸式:
/* a. 遞歸初始 m(n,j)
/* //背包容量為j、可選物品只有n,若背包容量j大於物品n的
/* //重量,則直接裝入;否則無法裝入。
/* m(n,j) = vn, j>=wn
/* m(n,j) = 0, 0<=j<wn
/* b. 遞歸式 m(i,j)
/* //背包容量為j、可選物品為i,i+1,...,n
/* //如果背包容量j<wi,則根本裝不進物品i,所以有:
/* m(i,j) = m(i+1,j), 0<=j<wi
/* //如果j>=wi,則在不裝物品i和裝入物品i之間做出選擇
/* 不裝物品i的最優值:m(i+1,j)
/* 裝入物品i的最優值:m(i+1, j-wi) + vi
/* 所以:
/* m(i,j) = max {m(i+1,j), m(i+1, j-wi) + vi}, j>=wi
/*
/************************************************************************/

#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
template <typename Type>
void Knapsack(Type* v, int *w, int c, int n, Type **m)
{
//遞歸初始條件
int jMax = min(w[n] - 1, c);
for (int j=0; j<=jMax; j++) {
m[n][j] = 0;
}

for (j=w[n]; j<=c; j++) {
m[n][j] = v[n];
}

//i從2到n-1,分別對j>=wi和0<=j<wi即使m(i,j)
for (int i=n-1; i>1; i--) {
jMax = min(w[i] - 1, c);
for (int j=0; j<=jMax; j++) {
m[i][j] = m[i+1][j];
}
for (j=w[i]; j<=c; j++) {
m[i][j] = max(m[i+1][j], m[i+1][j-w[i]]+v[i]);
}
}

m[1][c] = m[2][c];
if (c >= w[1]) {
m[1][c] = max(m[1][c], m[2][c-w[1]]+v[1]);
}

}

template <typename Type>
void TraceBack(Type **m, int *w, int c, int n, int* x)
{
for (int i=1; i<n; i++) {
if(m[i][c] == m[i+1][c]) x[i] = 0;
else {
x[i] = 1;
c -= w[i];
}
}
x[n] = (m[n][c])? 1:0;
}

int main(int argc, char* argv[])
{
int n = 5;
int w[6] = {-1, 2, 2, 6, 5, 4};
int v[6] = {-1, 6, 3, 5, 4, 6};
int c = 10;

int **ppm = new int*[n+1];
for (int i=0; i<n+1; i++) {
ppm[i] = new int[c+1];
}

int x[6];

Knapsack<int>(v, w, c, n, ppm);
TraceBack<int>(ppm, w, c, n, x);

return 0;
}
二.貪心演算法求解0-1背包問題
1.貪心法的基本思路:
——從問題的某一個初始解出發逐步逼近給定的目標,以盡可能快的地求得更好的解。當達到某演算法中的某一步不能再繼續前進時,演算法停止。
該演算法存在問題:
1).不能保證求得的最後解是最佳的;
2).不能用來求最大或最小解問題;
3).只能求滿足某些約束條件的可行解的范圍。

實現該演算法的過程:
從問題的某一初始解出發;
while 能朝給定總目標前進一步 do
求出可行解的一個解元素;
由所有解元素組合成問題的一個可行解;

2.例題分析

1).[背包問題]有一個背包,背包容量是M=150。有7個物品,物品可以分割成任意大小。
要求盡可能讓裝入背包中的物品總價值最大,但不能超過總容量。

物品 A B C D E F G
重量 35 30 60 50 40 10 25
價值 10 40 30 50 35 40 30

分析:
目標函數: ∑pi最大
約束條件是裝入的物品總重量不超過背包容量:∑wi<=M( M=150)
(1)根據貪心的策略,每次挑選價值最大的物品裝入背包,得到的結果是否最優?
(2)每次挑選所佔空間最小的物品裝入是否能得到最優解?
(3)每次選取單位容量價值最大的物品,成為解本題的策略。

<程序代碼:>(環境:c++)
#include<iostream.h>
#define max 100 //最多物品數
void sort (int n,float a[max],float b[max]) //按價值密度排序
{
int j,h,k;
float t1,t2,t3,c[max];
for(k=1;k<=n;k++)
c[k]=a[k]/b[k];
for(h=1;h<n;h++)
for(j=1;j<=n-h;j++)
if(c[j]<c[j+1])
{t1=a[j];a[j]=a[j+1];a[j+1]=t1;
t2=b[j];b[j]=b[j+1];b[j+1]=t2;
t3=c[j];c[j]=c[j+1];c[j+1]=t3;
}
}
void knapsack(int n,float limitw,float v[max],float w[max],int x[max])
{float c1; //c1為背包剩餘可裝載重量
int i;
sort(n,v,w); //物品按價值密度排序
c1=limitw;
for(i=1;i<=n;i++)
{
if(w[i]>c1)break;
x[i]=1; //x[i]為1時,物品i在解中
c1=c1-w[i];
}
}
void main()
{int n,i,x[max];
float v[max],w[max],totalv=0,totalw=0,limitw;
cout<<"請輸入n和limitw:";
cin>>n >>limitw;
for(i=1;i<=n;i++)
x[i]=0; //物品選擇情況表初始化為0
cout<<"請依次輸入物品的價值:"<<endl;
for(i=1;i<=n;i++)
cin>>v[i];
cout<<endl;
cout<<"請依次輸入物品的重量:"<<endl;
for(i=1;i<=n;i++)
cin>>w[i];
cout<<endl;
knapsack (n,limitw,v,w,x);
cout<<"the selection is:";
for(i=1;i<=n;i++)
{
cout<<x[i];
if(x[i]==1)
totalw=totalw+w[i];
}
cout<<endl;
cout<<"背包的總重量為:"<<totalw<<endl; //背包所裝載總重量
cout<<"背包的總價值為:"<<totalv<<endl; //背包的總價值
}
三.回溯演算法求解0-1背包問題
1.0-l背包問題是子集選取問題。
一般情況下,0-1背包問題是NP難題。0-1背包
問題的解空間可用子集樹表示。解0-1背包問題的回溯法與裝載問題的回溯法十分類
似。在搜索解空間樹時,只要其左兒子結點是一個可行結點,搜索就進入其左子樹。當
右子樹有可能包含最優解時才進入右子樹搜索。否則將右子樹剪去。設r是當前剩餘
物品價值總和;cp是當前價值;bestp是當前最優價值。當cp+r≤bestp時,可剪去右
子樹。計算右子樹中解的上界的更好方法是將剩餘物品依其單位重量價值排序,然後
依次裝入物品,直至裝不下時,再裝入該物品的一部分而裝滿背包。由此得到的價值是
右子樹中解的上界。
2.解決辦法思路:
為了便於計算上界,可先將物品依其單位重量價值從大到小排序,此後只要順序考
察各物品即可。在實現時,由bound計算當前結點處的上界。在搜索解空間樹時,只要其左兒子節點是一個可行結點,搜索就進入左子樹,在右子樹中有可能包含最優解是才進入右子樹搜索。否則將右子樹剪去。

回溯法是一個既帶有系統性又帶有跳躍性的的搜索演算法。它在包含問題的所有解的解空間樹中,按照深度優先的策略,從根結點出發搜索解空間樹。演算法搜索至解空間樹的任一結點時,總是先判斷該結點是否肯定不包含問題的解。如果肯定不包含,則跳過對以該結點為根的子樹的系統搜索,逐層向其祖先結點回溯。否則,進入該子樹,繼續按深度優先的策略進行搜索。回溯法在用來求問題的所有解時,要回溯到根,且根結點的所有子樹都已被搜索遍才結束。而回溯法在用來求問題的任一解時,只要搜索到問題的一個解就可以結束。這種以深度優先的方式系統地搜索問題的解的演算法稱為回溯法,它適用於解一些組合數較大的問題。
2.演算法框架:
a.問題的解空間:應用回溯法解問題時,首先應明確定義問題的解空間。問題的解空間應到少包含問題的一個(最優)解。
b.回溯法的基本思想:確定了解空間的組織結構後,回溯法就從開始結點(根結點)出發,以深度優先的方式搜索整個解空間。這個開始結點就成為一個活結點,同時也成為當前的擴展結點。在當前的擴展結點處,搜索向縱深方向移至一個新結點。這個新結點就成為一個新的活結點,並成為當前擴展結點。如果在當前的擴展結點處不能再向縱深方向移動,則當前擴展結點就成為死結點。換句話說,這個結點不再是一個活結點。此時,應往回移動(回溯)至最近的一個活結點處,並使這個活結點成為當前的擴展結點。回溯法即以這種工作方式遞歸地在解空間中搜索,直至找到所要求的解或解空間中已沒有活結點時為止。
3.運用回溯法解題通常包含以下三個步驟:
a.針對所給問題,定義問題的解空間;
b.確定易於搜索的解空間結構;
c.以深度優先的方式搜索解空間,並且在搜索過程中用剪枝函數避免無效搜索;
#include<iostream>

using namespace std;

class Knap
{
friend int Knapsack(int p[],int w[],int c,int n );

public:
void print()
{

for(int m=1;m<=n;m++)
{
cout<<bestx[m]<<" ";
}
cout<<endl;
};

private:
int Bound(int i);
void Backtrack(int i);

int c;//背包容量
int n; //物品數
int *w;//物品重量數組
int *p;//物品價值數組
int cw;//當前重量
int cp;//當前價值
int bestp;//當前最優值
int *bestx;//當前最優解
int *x;//當前解

};

int Knap::Bound(int i)
{
//計算上界
int cleft=c-cw;//剩餘容量
int b=cp;
//以物品單位重量價值遞減序裝入物品
while(i<=n&&w[i]<=cleft)
{
cleft-=w[i];
b+=p[i];
i++;
}
//裝滿背包
if(i<=n)
b+=p[i]/w[i]*cleft;
return b;
}

void Knap::Backtrack(int i)
{
if(i>n)
{
if(bestp<cp)
{
for(int j=1;j<=n;j++)
bestx[j]=x[j];
bestp=cp;
}
return;
}
if(cw+w[i]<=c) //搜索左子樹
{
x[i]=1;
cw+=w[i];
cp+=p[i];
Backtrack(i+1);
cw-=w[i];
cp-=p[i];
}
if(Bound(i+1)>bestp)//搜索右子樹
{
x[i]=0;
Backtrack(i+1);
}

}

class Object
{
friend int Knapsack(int p[],int w[],int c,int n);
public:
int operator<=(Object a)const
{
return (d>=a.d);
}

private:
int ID;
float d;
};

int Knapsack(int p[],int w[],int c,int n)
{
//為Knap::Backtrack初始化
int W=0;
int P=0;
int i=1;
Object *Q=new Object[n];
for(i=1;i<=n;i++)
{
Q[i-1].ID=i;
Q[i-1].d=1.0*p[i]/w[i];
P+=p[i];
W+=w[i];
}
if(W<=c)
return P;//裝入所有物品
//依物品單位重量排序
float f;
for( i=0;i<n;i++)
for(int j=i;j<n;j++)
{
if(Q[i].d<Q[j].d)
{
f=Q[i].d;
Q[i].d=Q[j].d;
Q[j].d=f;
}

}

Knap K;
K.p = new int[n+1];
K.w = new int[n+1];
K.x = new int[n+1];
K.bestx = new int[n+1];
K.x[0]=0;
K.bestx[0]=0;
for( i=1;i<=n;i++)
{
K.p[i]=p[Q[i-1].ID];
K.w[i]=w[Q[i-1].ID];
}
K.cp=0;
K.cw=0;
K.c=c;
K.n=n;
K.bestp=0;
//回溯搜索
K.Backtrack(1);
K.print();
delete [] Q;
delete [] K.w;
delete [] K.p;
return K.bestp;

}

void main()
{
int *p;
int *w;
int c=0;
int n=0;
int i=0;
char k;
cout<<"0-1背包問題——回溯法 "<<endl;
cout<<" by zbqplayer "<<endl;
while(k)
{
cout<<"請輸入背包容量(c):"<<endl;
cin>>c;
cout<<"請輸入物品的個數(n):"<<endl;
cin>>n;
p=new int[n+1];
w=new int[n+1];
p[0]=0;
w[0]=0;

cout<<"請輸入物品的價值(p):"<<endl;
for(i=1;i<=n;i++)
cin>>p[i];

cout<<"請輸入物品的重量(w):"<<endl;
for(i=1;i<=n;i++)
cin>>w[i];

cout<<"最優解為(bestx):"<<endl;
cout<<"最優值為(bestp):"<<endl;
cout<<Knapsack(p,w,c,n)<<endl;
cout<<"[s] 重新開始"<<endl;
cout<<"[q] 退出"<<endl;
cin>>k;
}
四.分支限界法求解0-1背包問題
1.問題描述:已知有N個物品和一個可以容納M重量的背包,每種物品I的重量為WEIGHT,一個只能全放入或者不放入,求解如何放入物品,可以使背包里的物品的總效益最大。

2.設計思想與分析:對物品的選取與否構成一棵解樹,左子樹表示不裝入,右表示裝入,通過檢索問題的解樹得出最優解,並用結點上界殺死不符合要求的結點。

#include <iostream.h>

struct good
{
int weight;
int benefit;
int flag;//是否可以裝入標記
};

int number=0;//物品數量
int upbound=0;
int curp=0, curw=0;//當前效益值與重量
int maxweight=0;
good *bag=NULL;

void Init_good()
{
bag=new good [number];

for(int i=0; i<number; i++)
{
cout<<"請輸入第件"<<i+1<<"物品的重量:";
cin>>bag[i].weight;
cout<<"請輸入第件"<<i+1<<"物品的效益:";
cin>>bag[i].benefit;
bag[i].flag=0;//初始標志為不裝入背包
cout<<endl;
}

}

int getbound(int num, int *bound_u)//返回本結點的c限界和u限界
{
for(int w=curw, p=curp; num<number && (w+bag[num].weight)<=maxweight; num++)
{
w=w+bag[num].weight;
p=w+bag[num].benefit;
}

*bound_u=p+bag[num].benefit;
return ( p+bag[num].benefit*((maxweight-w)/bag[num].weight) );
}

void LCbag()
{
int bound_u=0, bound_c=0;//當前結點的c限界和u限界

for(int i=0; i<number; i++)//逐層遍歷解樹決定是否裝入各個物品
{
if( ( bound_c=getbound(i+1, &bound_u) )>upbound )//遍歷左子樹
upbound=bound_u;//更改已有u限界,不更改標志

if( getbound(i, &bound_u)>bound_c )//遍歷右子樹
//若裝入,判斷右子樹的c限界是否大於左子樹根的c限界,是則裝入
{
upbound=bound_u;//更改已有u限界
curp=curp+bag[i].benefit;
curw=curw+bag[i].weight;//從已有重量和效益加上新物品
bag[i].flag=1;//標記為裝入
}
}

}

void Display()
{

cout<<"可以放入背包的物品的編號為:";
for(int i=0; i<number; i++)
if(bag[i].flag>0)
cout<<i+1<<" ";
cout<<endl;
delete []bag;
}

㈤ 0/1鑳屽寘闂棰樷斺斿姩鎬佽勫垝銆佸洖婧銆佸垎鏀闄愮晫娉曞規瘮

鍋囧畾n涓鍟嗗搧閲嶉噺鍒嗗埆涓簑 0 , w 1 , ..., w n-1 錛屼環鍊煎垎鍒涓簆 0 , p 1 , ..., p n-1 錛岃儗鍖呰澆閲嶉噺涓篗銆傛庢牱閫夋嫨鍟嗗搧緇勫悎錛屼嬌寰椾環鍊兼渶楂橈紵

鏈澶у肩殑浼扮畻娉曪紙璺熷垎鏀闄愮晫娉曟湰璐ㄤ笂鏄涓鏍風殑錛

鍚戜笂鍥炴函鐨勬柟娉

w_cur鈥斺旇〃紺哄綋鍓嶆e湪鎼滅儲鐨勯儴鍒嗚В涓杞鍏ョ殑鎬婚噸閲
p_cur鈥斺斿綋鍓嶆諱環鍊
p_est鈥斺旈儴鍒嗚В鍙鑳借揪鍒扮殑鏈澶т環鍊肩殑浼拌″
p_total鈥斺斿綋鍓嶆悳緔㈠埌鐨勬墍鏈夊彲琛岃В涓鐨勬渶澶т環鍊礆紝鏄褰撳墠鐩鏍囧嚱鏁扮殑涓婄晫
y k 銆亁 k 鈥斺旈儴鍒嗚В鐨勭琸涓鍒嗛噺鍙婂叾鍓鏈
k鈥斺旇〃紺哄綋鍓嶆悳緔㈡繁搴

M = 50
鍟嗗搧閲嶉噺鍒嗗埆涓5,15,25,27,30
鍟嗗搧浠峰煎垎鍒涓12,30,44,46,50
涓婇潰宸茬粡鎸夌収鍗曚綅閲嶉噺浠峰奸掑噺欏哄簭鎺掑垪銆

姣忎釜緇撶偣閮藉寘鍚濡備笅淇℃伅錛
  S 1 鈥斺斿綋鍓嶉夋嫨瑁呭叆鑳屽寘鐨勫晢鍝侀泦鍚
  S 2 鈥斺斿綋鍓嶄笉閫夋嫨瑁呭叆鑳屽寘鐨勫晢鍝侀泦鍚
  S 3 鈥斺斿綋鍓嶅皻寰呴夋嫨鐨勫晢鍝侀泦鍚
  k鈥斺旀悳緔㈡繁搴
  b鈥斺斾笂鐣
bound鈥斺斾竴涓鍙琛岃В鐨勫彇鍊礆紝褰撳仛鍓鏋濈殑鏍囧噯

杈撳叆鎻忚堪:

杈撳嚭鎻忚堪:

杈撳叆渚嬪瓙:

杈撳嚭渚嬪瓙:

㈥ 動態規劃中的0-1背包問題怎麼去理解要求給出具體實例和詳細步驟。。。

* 一個旅行者有一個最多能用M公斤的背包,現在有N件物品,
它們的重量分別是W1,W2,...,Wn,
它們的價值分別為P1,P2,...,Pn.
若每種物品只有一件求旅行者能獲得最大總價值。
輸入格式:
M,N
W1,P1
W2,P2
......
輸出格式:
X
*/

因為背包最大容量M未知。所以,我們的程序要從1到M一個一個的試。比如,開始任選N件物品的一個。看對應M的背包,能不能放進去,如果能放進去,並且還有多的空間,則,多出來的空間里能放N-1物品中的最大價值。怎麼能保證總選擇是最大價值呢?看下錶。
測試數據:
10,3
3,4
4,5
5,6

c[i][j]數組保存了1,2,3號物品依次選擇後的最大價值.

這個最大價值是怎麼得來的呢?從背包容量為0開始,1號物品先試,0,1,2,的容量都不能放.所以置0,背包容量為3則裡面放4.這樣,這一排背包容量為4,5,6,....10的時候,最佳方案都是放4.假如1號物品放入背包.則再看2號物品.當背包容量為3的時候,最佳方案還是上一排的最價方案c為4.而背包容量為5的時候,則最佳方案為自己的重量5.背包容量為7的時候,很顯然是5加上一個值了。加誰??很顯然是7-4=3的時候.上一排 c3的最佳方案是4.所以。總的最佳方案是5+4為9.這樣.一排一排推下去。最右下放的數據就是最大的價值了。(注意第3排的背包容量為7的時候,最佳方案不是本身的6.而是上一排的9.說明這時候3號物品沒有被選.選的是1,2號物品.所以得9.)

從以上最大價值的構造過程中可以看出。

f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}這就是書本上寫的動態規劃方程.這回清楚了嗎?

下面是實際程序:

#include<stdio.h>
int c[10][100];/*對應每種情況的最大價值*/
int knapsack(int m,int n)
{
int i,j,w[10],p[10];
for(i=1;i<n+1;i++)
scanf("\n%d,%d",&w[i],&p[i]);
for(i=0;i<10;i++)
for(j=0;j<100;j++)
c[i][j]=0;/*初始化數組*/
for(i=1;i<n+1;i++)
for(j=1;j<m+1;j++)
{
if(w[i]<=j) /*如果當前物品的容量小於背包容量*/
{
if(p[i]+c[i-1][j-w[i]]>c[i-1][j])

/*如果本物品的價值加上背包剩下的空間能放的物品的價值*/

/*大於上一次選擇的最佳方案則更新c[i][j]*/
c[i][j]=p[i]+c[i-1][j-w[i]];
else
c[i][j]=c[i-1][j];
}
else c[i][j]=c[i-1][j];
}
return(c[n][m]);

}
int main()
{
int m,n;int i,j;
scanf("%d,%d",&m,&n);
printf("Input each one:\n");
printf("%d",knapsack(m,n));
printf("\n");/*下面是測試這個數組,可刪除*/
for(i=0;i<10;i++)
for(j=0;j<15;j++)
{
printf("%d ",c[i][j]);
if(j==14)printf("\n");
}
system("pause");
}

㈦ 0-1鑳屽寘闂棰樺叆闂ㄨ﹁В

緗戜笂濂藉氬叧浜庤儗鍖呴棶棰樼殑瑙i噴錛岃嚜宸變篃鐪嬩簡錛屾劅瑙夎В閲婄殑涓嶅規槗閫氫織鏄撴噦錛屾墍浠ヨ嚜宸辨潵鍐欎竴涓闈炲父瀹規槗鎳傚緱銆

0-1鑳屽寘闂棰樿寸殑鏄錛岀粰瀹氳儗鍖呭歸噺W錛屼竴緋誨垪鐗╁搧{weiht,value}錛屾瘡涓鐗╁搧鍙鑳藉彇涓浠訛紝鑾峰彇鏈澶у箋

閲囩敤鍔ㄦ佽勫垝奼傝В錛屽姩鎬佽勫垝鐨勪竴鑸瑙勫緥閮芥槸錛

鍦ㄤ粈涔堜粈涔堝墠i涓鐘舵佷笅鐨勬渶澶у兼垨鑰呮渶灝忓肩殑鍓嶆彁涓嬶紝鐒跺悗鍐嶆妸i鐨勭姸鎬佺殑鍊兼眰鍑烘潵銆

榪欓噷鎴戜滑瀹氫箟涓涓鍑芥暟錛岃〃紺虹姸鎬併

m(1,2,3,4..i)(w)琛ㄧず鏈1鍙,2鍙,3鍙,4鍙....i鍙風墿鍝侊紝鑳屽寘瀹歸噺涓簑鐨勬椂鑳藉熷彇寰楃殑鏈澶у箋備婦渚嬭存槑錛

鍋囪1錛2,3,4,5鍙風墿鍝侊紝瀹冧滑鐨勯噸閲忓垎鍒鏄2,2,6,5,4錛岀敤weight(i)琛ㄧず錛屽畠浠鐨勪環鍊煎垎鍒鏄6,3,5,4,6鐢╲alue(i)琛ㄧず

m(1)(1)琛ㄥ彧鏈1鍙風墿鍝侊紝鑳屽寘瀹歸噺涓1鐨勬椂鍊欙紝鏈澶у箋傛樉鐒訛紝

m(1)(1) = 0錛屽洜涓鴻儗鍖呭歸噺灝忎簬2錛屾墍浠ユ渶澶у間負0銆

m(1)(2) = 6, 姝ゆ椂鑳屽寘瀹歸噺絳変簬2錛岃呬笅1鍙風墿鍝侊紝鏈澶у間負6錛屾帴涓嬫潵

m(1)(3) = 6,m(1)(4) = 6錛...m(1)(..) = 6,鍥犱負鍙鏈変竴浠剁墿鍝侊紝鏈澶т負6銆

m(1,2)(1),m(1,2)(2),m(1,2)(3)琛ㄧず鏈夌墿鍝1鍙鳳紝2鍙鳳紝鑳屽寘瀹歸噺鍒嗗埆涓1,2,3鐨勬椂鍊欐渶澶у箋

鏈澶у煎拰鐗╁搧鐨勬暟閲忕浉鍏籌紝涔熷拰鑳屽寘瀹歸噺鐩稿叧銆

榪欓噷蹇呴』寮鴻皟涓涓嬶紝m(1,2,3,...i)(w) 琛ㄧず鏈1,2,3,4....i錛岃繖涔堝氱墿鍝佸彲閫夛紝鏈蹇呭叏閮ㄨ呰繘鍘葷殑鎯呭喌涓(鍙楅檺浜巜)鐨勬渶澶у箋

鎺ヤ笅鏉ヨㄨ哄湪1,2,3.....i鐗╁搧鐨勬渶澶у箋傚逛簬絎琲浠剁墿鍝侊紝鑳屽寘瀹歸噺涓篧錛屾湁涓ょ嶆儏鍐碉紝

1錛変笉鎶婄琲浠剁墿鍝佽呰繘鑳屽寘錛岄偅涔堟ゆ椂錛屽彧鏈1,2,3,4,,,,i-1浠剁墿鍝侊紝鑳屽寘鐨勬渶澶у兼槸m(1,2,3,4,5....i-1)(W)銆傛ゆ椂錛屼笉綆W澶氫箞澶э紝鍗充嬌鍜屽畤瀹欎竴鏍峰ぇ錛岃儗鍖呴噷鐨勪環鍊間箣鍜1,2,3,4,5..i-1榪欎簺鐗╁搧鐩稿叧銆

2錛夋妸絎琲浠剁墿鍝佽呰繘鍘匯傛棦鐒舵妸i浠剁墿鍝佽呰繘鑳屽寘錛岄偅涔1,2,3,4.....i-1鐗╁搧鍙鑳藉崰鐢 W-weight(i) 榪欎箞澶氶噸閲忎簡銆傝繖涓鏃跺欙紝

涔嬪墠鐨1,2,3,4......i-1鐗╁搧鍦ㄨ儗鍖呭歸噺涓猴紙W-weight(i)錛変笅鐨勬渶澶у間負m(1,2,3.......i-1)[ W - weight(i) ]銆

姝ゆ椂鑳屽寘鐨勬渶澶у煎氨鏄 絎琲浠剁墿鍝佺殑浠峰紇alue(i)鍔犱笂

鍓1,2,3,4....i-1浠剁墿鍝佸湪鑳屽寘瀹歸噺涓猴紙W-weight(i) 涓嬬殑鏈澶у糾(1,2,3.......i-1)[ W - weight(i) ]

m錛1,2,3,4.......i-1,i)(W)= m(1,2,3.......i-1)[ W - weight(i) ] +   value(i) ;

鐒跺悗鎴戜滑姣旇緝涓涓嬶紝鎯呭喌1錛2錛夌殑鏈澶у煎氨鍙浠ヤ簡 鍗

m(1,2,3,4....i-1,i)(W) = max[  m(1,2,3.......i-1)[ W - weight(i) ] +   value(i) , m(1,2,3,4,5....i-1)(W) ]銆 

榪欓噷鏈変漢浼氳達紝鍓1,2,3,4.....i-1浠剁墿鍝佸湪W-weight鎴栬匴鐨勫歸噺涓嬫庝箞奼傚晩銆

榪欓噷灝辮村埌鍔ㄦ佽勫垝鐨勭偣涓娿傚姩鎬佽勫垝鏈夌偣鏁板﹀綊綰蟲硶鐨勬劅瑙夛紝涓嶈繃鏄浠庡悗鍚戝墠鎺ㄥ埌錛岃佹眰瑙i錛屽厛奼傝Вi-1,錛涜佹眰瑙i-1錛屽厛奼傝Вi-2錛岃繖鏍蜂竴姝ヤ竴姝ュ埌2,1銆傚洜姝ら渶瑕佺粰瀹氬垵濮嬬姸鎬併傛垜浠涓鐩寸敤1,2,3,4.....i-1琛ㄧず鍓嶢-1浠剁墿鍝侊紝澶楹葷儲錛岀洿鎺ョ敤i-1琛ㄧず濂戒簡銆

m(1,2,3,4....i-1)(w) ====(涔﹀啓鏂逛究)>m(i-1)(w)錛岃繖鏍蜂笂闈㈢殑鐘舵佽漿縐繪柟紼嬪氨鍑烘潵銆

m(i)(W) = max( m(i-1)(W- weight(i))+value(i), m(i-1)(w) )

榪欐牱錛岀姸鎬佺殑杞縐繪柟紼嬪氨鍑烘潵銆傝繖閲屼笉寰椾笉璇翠笅錛岀綉涓婄殑鍏朵粬鏁欑▼榪欎竴鐐逛笂璇寸殑涓嶅熶粩緇嗭紝涓婃潵灝辨悶涓涓

f[i-1][j] = max(f[i-1][j-w(i)]+value[i],f[i-1][j])銆傝皝鐪嬬殑鎳傚晩銆

榪欓噷鎴戜滑閽堝逛笂闈㈢殑鏁板肩粰鍑哄叿浣撶殑奼傝В榪囩▼銆傞栧厛緇欏嚭鐗╁搧鐨勫嚱鏁板箋

weight(1) = 2,value(1) = 6,

weight(2) = 2,value(2) = 3,

weight(3) = 6,value(3) = 5,

weight(4) = 5,value(4) = 4,

weight(5) = 4,value(5) = 6,

閭d箞鏈澶у煎嚱鏁

m(1)(1) = 0錛涚墿鍝侀噸閲忎負2.

m(1)(2) = 6, 鐗╁搧鎮板ソ鏀懼叆鑳屽寘銆

m(1)(3) = 6錛宮(1)(4) = 6...錛屽彧鏈1鍙風墿鍝侊紝鏈澶у煎彧鑳戒負6銆傜幇鍦ㄨ冭檻鏈夌2浠剁墿鍝佺殑鎯呭喌錛岀幇鍦ㄦ湁涓や歡鐗╁搧錛宮鍑芥暟琛ㄧず涓

m(1,2)(w)銆

鏍規嵁涔嬪墠鎵璇 1錛夛紝濡傛灉涓嶆妸2鍙風墿鍝佹斁鍏ワ紝閭i棶棰樺洖鍒板彧鏈1鍙風墿鍝佺殑鎯呭喌

閭d箞

m(1)(1) = 0,1鍙風墿鍝佹斁涓嶈繘錛

m(1)(2) = 6, 1鍙風墿鍝佹斁榪涜儗鍖呫

m(1)(3) = 6, 1鍙風墿鍝佹斁榪涘歸噺涓3鐨勮儗鍖

m(1)(4) = 6, 1鍙風墿鍝佹斁榪涘歸噺涓4鐨勮儗鍖呫

鏍規嵁涔嬪墠鎵璇2錛夛紝鎶2鍙風墿鍝佹斁鍏ワ紝姝ゆ椂闇瑕 1鍙風墿鍝佸湪鑳屽寘瀹歸噺w鍑忓幓2鍙風墿鍝佺殑瀹歸噺weight(2),鍗 w-2鐨勯棶棰樸

m(1)(1 - 2) = 0,鏄劇劧錛屾ゆ椂鑳屽寘鎬誨歸噺涓1錛岃繕鏈夊噺鍘2鍙風墿鍝佺殑瀹歸噺2錛1-2=-1 錛屾樉鐒舵斁涓嶈繘鍘匯

m(1)(2 - 2) = 0,鏄劇劧錛岃儗鍖呯殑瀹歸噺鍑忓幓2鍙風墿鍝佺殑瀹歸噺鍚庯紝娌℃湁鍓╀綑錛屽氨鏄璇村彧鑳芥斁2鍙風墿鍝侊紝姝ゆ椂鑳屽寘鐨勬渶澶у

m(1,2)(2)  =  max(m(1,2)(2-2)+value(2),  m(1)(2))= max(0+3,6) = 6銆傚氨鏄璇達紝鍦ㄦ湁1,2涓や歡鐗╁搧錛岃儗鍖呭歸噺涓2鐨勬儏鍐典笅錛屾渶澶у間負6銆

緇х畫鑰冭檻鑳屽寘瀹歸噺涓3錛岀涓縐嶆儏鍐電殑宸茬粡璁ㄨ恆傜幇鍦ㄨㄨ虹浜岀嶆儏鍐碉紝鎶2鍙風墿鍝佹斁鍏ヨ儗鍖咃紝灝辮佸墿涓媤-2鐨勫歸噺緇1鍙蜂簡銆

m(1,2)(w-2)= m(1,2)(3-2)=m(1,2)(1)  = 0, value(2) = 3鍥犳わ紝

m(1,2)(3) = max[ m(1,2)(3-2)+value(2),m(1)(3)] = max(0+3,6) = 6銆

緇х畫鑰冭檻鑳屽寘瀹歸噺涓4錛屽悓鐞嗭紝絎涓縐嶆儏鍐佃ㄨ猴紝鍙璁ㄨ虹浜岀嶆儏鍐碉紝鎶2鍙風墿鍝佹斁鍏ヨ儗鍖咃紝灝辮佸墿涓媤-2鐨勫歸噺緇1鍙蜂簡銆

m(1,2)(4-2)=m(1,2)(2)=6,value(2) = 3

m(1,2)(4) = max[ m(1,2)(4-2)+value(2),m(1)(4)]=max[m(1,2)(2)+value(2),m(1)(4)] = max(6+3,6) = 9;

姝ゆ椂m(1,2)(4) = 9;涔嬪悗錛岃儗鍖呭歸噺涓5錛6,7錛屻傜殑鏃跺欙紝1,2鐗╁搧閮芥斁榪涘幓錛屾渶澶у間笉鍐嶆敼鍙橈紝閮芥槸9

m(1,2)(5) = 9錛宮(1,2)(6) = 9錛宮(1,2)(7) = 9錛宮(1,2)(8) = 9

鍚岀悊錛寃eight(3) = 6,value(3)=5

m(1,2,3)(1) = max[ m(1,2,3)(1-6)+value(3),m(1,2)(1) ] = 0

m(1,2,3)(2) = max[ m(1,2,3)(2-6)+value(3),m(1,2)(2)  ] =6

m(1,2,3)(3) = max[ m(1,2,3)(3-6)+value(3),m(1,2)(3)  ] =6

m(1,2,3)(4) = max[ m(1,2,3)(4-6)+value(3),m(1,2)(4)  ] =9

m(1,2,3)(5) = max[ m(1,2,3)(5-6)+value(3),m(1,2)(5)  ] =9

m(1,2,3)(6) = max[ m(1,2,3)(6-6)+value(3),m(1,2)(6)  ] = 9

m(1,2,3)(7) = max[ m(1,2,3)(7-6)+value(3),m(1,2)(7)  ] = max[m(1,2,3)(1)+5,9] = max[0+5,9]=9

m(1,2,3)(8) = max[ m(1,2,3)(8-6)+value(3),m(1,2)(8)  ] = max[m(1,2,3)(2)+5,9] = max[6+5,9]=11;

鍓╀笅鐨勬帹瀵奸兘鏄濡傛わ紝鏍規嵁鑳屽寘瀹歸噺涓姝ヤ竴姝ョ殑鎺ㄥ煎嵆鍙銆

熱點內容
混沌珠演算法 發布:2024-11-26 08:29:17 瀏覽:163
阿里雲解析不到伺服器 發布:2024-11-26 07:57:59 瀏覽:493
python矩陣的行數 發布:2024-11-26 07:56:25 瀏覽:355
街頭籃球手游腳本 發布:2024-11-26 07:51:18 瀏覽:752
閃迪加密器 發布:2024-11-26 07:44:08 瀏覽:553
我的世界伺服器顯示村民名字 發布:2024-11-26 07:37:16 瀏覽:479
php注冊與登錄 發布:2024-11-26 07:31:21 瀏覽:796
基金賬戶如何配置 發布:2024-11-26 07:29:58 瀏覽:181
用電腦怎麼刷汽車行車電腦配置 發布:2024-11-26 07:24:14 瀏覽:689
客戶端ip和伺服器ip地址怎麼設置 發布:2024-11-26 07:18:25 瀏覽:685