1.問題重述
給定n個物品,價值分別是:v1,v2,…,vn,重量分別是:w1,w2,…,wn。在物品不可分割的情況下,挑選物品放入承重為w的揹包,使得揹包內物品的價值最大,且揹包內物品的總重量小於w.
2.解決方案
本問題可用多種方法解決,這裡採用遺傳演算法來求解,以下是遺傳演算法的流程圖:
要採用遺傳演算法,則首先確定以下幾個要素:染色體的編碼方法、適值函式、染色體交叉和變異採用的方案、選擇策略
2.1 染色體的編碼方法
基因編碼的方法都有:二進位制、整數編碼、順序編碼、 實數編碼等
對於01揹包問題,由於每乙個物體都有選或者不選兩種情況,即可以用0、1來表示選擇或是沒有選擇。故可使用二進位制的編碼方法來對染色體編碼,且染色體長度為物體個數。
def
initpopulation
(self)
:"""初始化種群"""
self.lives =
for i in
range
(self.lifecount)
: gene =
[random.randint(0,
1)for x in
range
(self.genelenght)
]# 初始化染色體
life = life(gene)
# 生成個體
# 擴充套件種群
2.2 適值函式的選擇
在確定適值函式時,首先要確定是求最小值優化問題還是求最大值優化問題,當求最大值優化問題時,可直接將目標函式當做適值函式,求最小值優化問題時,通過變換將其變為求最大值優化問題。
確定目標函式時,要先確定求解目標以及約束條件。此問題的目標是求乙個x=(x1,x2…xn)(xi為0或1),從而使得v(總價值)最大,而約束條件則是w(揹包承重)。以下為我的目標函式:
f (x
)=∑i
=1nx
i∗vi
∑i=1
nxi∗
wi⩽w
f(x)=\sum_^n x_i*v_i \ \ \ \ \ \ \ \ \ \ \ \ \sum_^n x_i*w_i\leqslant w
f(x)=i
=1∑n
xi
∗vi
i=1∑
nxi
∗wi
⩽wf(x
)=∑i
=1nx
i∗vi
∑i=1
nxi∗
wi+1
−w∑i
=1nx
i∗wi
>
wf(x)=\frac^n x_i*v_i} ^n x_i*w_i+1-w} \ \ \ \ \ \ \ \ \ \ \ \ \sum_^n x_i*w_i>w
f(x)=∑
i=1n
xi
∗wi
+1−w
∑i=1
nxi
∗vi
i=
1∑n
xi∗
wi>
w為了讓物體盡可能裝滿揹包,故又加入了罰值函式:
p (x
)=1−
∣∑i=
1nxi
∗wi−
w∣δp(x)=1-\frac^n x_i*w_i-w\rvert} δ
p(x)=1
−δ∣∑
i=1n
xi
∗wi
−w∣
其中δ=ma
xδ=max\^*w_i-w\rvert\}
δ=ma
x從中不難看出,當總重越接近w時,p(x)越接近1。
最終,適值函式確定為:
f (x
)=f(
x)∗p
(x)f(x)=f(x)*p(x)
f(x)=f
(x)∗
p(x)
**如下:
def
matchfun
(self)
:"""適值函式"""
max =
max(self.allgoods,
abs(
sum(self.goods[i][0
]for i in
range
(len
(self.goods)))
- self.allgoods)
)return
lambda life: self.price(life.gene)[1
]/(self.price(life.gene)[0
]+1-self.allgoods)
*\ (1-
abs(self.price(life.gene)[0
]-self.allgoods)
/max) \
if self.price(life.gene)[0
]>self.allgoods \
else self.price(life.gene)[1
]*(1
-abs
(self.price(life.gene)[0
]-self.allgoods)
/max)
此函式的返回值為乙個由lambda定義的函式,這樣可以將它作為形參傳遞到其他類中呼叫,有點類似於c++中的函式指標。
2.3 交叉
此處採取的交叉策略是隨機從其他染色體上擷取一段基因,與原染色體上的此段基因片段交換,來得到新染色體
def
cross
(self, parent1, parent2)
:"""交叉"""
index1 = random.randint(
0, self.genelenght -1)
index2 = random.randint(index1, self.genelenght -1)
newgene =
newgene.extend(parent1.gene[
:index1]
) newgene.extend(parent2.gene[index1:index2]
) newgene.extend(parent1.gene[index2:])
self.crosscount +=
1return newgene # 返回交叉後的parent1.gene
2.4 變異
此處採取的變異策略是隨機改變染色體中一處基因的值(有一定概率此染色體會繼續變異,故此處用了遞迴)
def
mutation
(self, gene)
:"""突變,兩個基因互換位置"""
index1 = random.randint(
0, self.genelenght -1)
newgene = gene[:]
# 產生乙個新的基因序列,以免變異的時候影響父種群
newgene[index1]
=(newgene[index1]+1
)%2if random.random(
)< self.mutationrate:
self.mutation(newgene)
self.mutationcount +=
1return newgene
3. 原始碼
原始碼見
遺傳演算法解決揹包問題
總體思想與之前的相似,評價函式就是物品的價值之和,但要注意一旦物品的重量大於揹包的重量,那麼該條染色體的倖存概率為0 基因就是每乙個物品是否選擇,這裡預設有10條染色體在比較,並且每一條染色體上的第i個基因就是代表第i個物品是否選擇 突變就是隨機選擇的染色體的隨機位置由0變1,由1變0 另外建議把變...
遺傳演算法 01揹包問題 C
include include include include include using namespace std const int pack max w 80 揹包最大承受重量 const int pack max v 75 揹包最大承受容積 const int num 32 物品數 con...
tsp問題 遺傳演算法解決
tsp問題最簡單的求解方法是列舉法。它的解是多維的 多區域性極值的 趨於無窮大的複雜解的空間,搜尋空間是n個點的所有排列的集合,大小為 n 1 可以形象地把解空間看成是乙個無窮大的丘陵地帶,各山峰或山谷的高度即是問題的極值。求解tsp,則是在此不能窮盡的丘陵地帶中攀登以達到山頂或谷底的過程。這一篇將...