在这个0-1背包的例子中,假设有12件物品,质量分别为2磅、5磅、18磅、3磅、2磅、5磅、10磅、4磅、11磅、7磅、14磅、6磅,价值分别为5元、10元、13元、4元、3元、11元、13元、10元、8元、16元、7元、4元,包的最大允许质量是46磅。
clear
clc
a = 0.95;
k = [5;10;13;4;3;11;13;10;8;16;7;4]; %价值
k = -k; %模拟退火算法是求解最小值,故取负值
d = [2;5;18;3;2;5;10;4;11;7;14;6]; %质量
restriction = 46;
num = 12;
sol_new = ones(1,num); %生成初始解%E_new是新解的目标函数值
E_current = inf;%E_current是当前解对应的目标函数值(即背包中物品总价值)
E_best = inf;%E_best是最优解
sol_current = sol_new;%当前对应解先用初始解代替
sol_best = sol_new;%最佳解也用初始解代替
t0 = 97;%起始温度
tf = 3;%最低温度
t = t0;%起始温度
p = 1;
while t >= tf %温度不断下降,退火的精髓
for r = 1:100
%产生随机扰动
tmp = ceil(rand*num);%ceil函数的作用是朝正无穷方向取整,即将m/n的结果向正无穷方向取整,如m/n=3.12,则ceil(m/n)的结果为4。
%确定随机选几个因为是个数所以要取整
sol_new(1,tmp) = ~sol_new(1,tmp); %列表里的某个值等于取相反,随机舍弃一个。
%检查是否满足约束
while 1
q = (sol_new * d <= restriction);
if ~q
p = ~p; %实现交错着逆转头尾的第一个1
tmp = find(sol_new == 1);%b=find(a),a是一个矩阵,查询非零元素的位置,如果X是一个行向量,则返回一个行向量,否则,返回一个列向量。如果X全是零元素或者是空数组,则返回一个空数组,例子如下所示,也可以用b=find(a>2),这句的意思是在a中找到比较2大的元素;
if p
sol_new(1,tmp(1)) = 0;
else
sol_new(1,tmp(end)) = 0;
end
else
break %如果小于设定的上限质量break
end
end
%计算背包中的物品价值
E_new = sol_new * k;%总价值
if E_new < E_current
E_current = E_new;
sol_current = sol_new;
if E_new < E_best
E_best = E_new;
sol_best = sol_new;
end
else
if rand < exp( -(E_new - E_current) / t)%以一定概率选择是否接受翻山。
E_current = E_new;
sol_surrent = sol_new;
else
sol_new = sol_current;
end
end
end
t = t * a; %温度衰减速度
end
disp('最优解为:');
sol_best
disp('物品总价值等于:');
val = -E_best;
disp(val);
disp('背包中物品重量是:');
disp(sol_best * d);
最优解为:
sol_best =
1 1 0 0 1 1 1 1 1 1 0 0
物品总价值等于:
76
背包中物品重量是:
46