基于模拟退火的交巡警平台调度问题

        2011年数学建模国赛B题的交巡警平台问题是一个经典的整数规划问题,常规的方法是用整数规划求解。但为了练习一下智能算法,我还是决定用模拟退火针对该问题的第二问写一些求解心得。一方面作为学习的记录,另一方面也给有同样问题的朋友们一些启发。

 欧式距离计算

        首先,初始化数据。各个节点之间有些有路线有些没有路线,根据给出的data计算出有路线的节点之间的距离。该距离将在下文迪杰斯特拉最短路径法的有向图作为权重使用。

%% 数据初始化
pos = readmatrix('data.xls','Sheet','全市交通路口节点数据','Range','B2:C93'); % A区各点坐标
point = readmatrix('data.xls','Sheet','全市交通路口的路线','Range','A2:B144'); % 路径节点
p_start = []; % 开始点
p_end = []; % 结束点
for i = 1:143
    if point(i,2) <= 92
        p_start = [p_start, point(i,1)];
        p_end = [p_end, point(i,2)]; % 筛选A市区范围内的路径
    end
end
d = sqrt((pos(p_start,1) - pos(p_end,1)).^2 + (pos(p_start,2) - pos(p_end,2)).^2); % 路径距离

 迪杰斯特拉最短路径法

         根据迪杰斯特拉最短路径法,画出各节点之间路径的有向图,并根据有向图得到最短路径矩阵D。

%% 迪杰斯特拉最短路径法
s = p_start; % 开始点
t = p_end; % 结束点
w = d; % 权重,本题代表路径距离
G = graph(s,t,w); % 生成有向图
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 1); % 做出有向图
D = distances(G);   % 最短路径矩阵

        

        图其实不重要,对我们真正有用的,是那个最短路径矩阵D。根据D,我们才有方法建立优化模型。

        该问题简化后可以如下表述:节点1-20(代表交巡警平台)中派13个到13个指定节点(全市区出入口位置)的最优方案。

         主要有两种主要思路,第一种是不同时出发,让总路程最短,该思路省油;第二种思路是同时出发,让总时间最短,该思路省时间。第一种思路建模比较容易,优化函数怎么写比较直观。第二种思路更加贴合实际,但是模型的优化函数建立比较麻烦,且假设警车速度都相同本质上也不是那么合理。因此我采用第一种思路求解。

优化目标设置

%% 围堵方案目标:总路径最短
vital_point = readmatrix('data.xls','Sheet','全市区出入口的位置','Range','C2:C14'); % 交通要道位置
police_point = 1:1:20; police_point = police_point.'; % 交巡警平台位置
% distance_per = D(police_point, vital_point); % 每个交警平台围堵特点节点的距离
% distance_total = sum(distance_per)  % 构造总路径函数obj_fun

其中vital_point就是全市出入口位置。police_point代表交巡警平台。

优化函数

        优化函数中,将police_point设置为决策变量x,因为police_point是在20个中选13个,即对象不固定,而vital_point虽然在顺序上不固定,但是对象是固定的。

        此时的x是一个序列,每一个值对应的交巡警平台即去向vital_point中相同索引的节点。该序列在1-20中挑选13个数字随机排序。

function f = obj_fun(x,D,vital_point) % 目标函数
    f = 0;
    for i = 1:13
        f = f + D(vital_point(i),x(i));
    end
end

罚函数

        罚函数是处理约束条件的函数,本题中没有约束函数,可以让CV=0。遇到有约束条件的问题,罚函数可以按照如下形式书写。 

function CV = obj_fun_CV(x)  % 约束条件函数
    G1 = (g1(x) > 0).*(g1(x)); % 约束条件1的罚函数
    G2 = (g2(x) ~= 0).*(g2(x)); % 约束条件2的罚函数
    CV = G1+G2; % 罚函数累加
end

模拟退火算法过程

第一步,设置参数

        设置句柄函数和退火过程的物理量参数。

%% 设置求解问题的参数
problem.numVar = 13;       %变量个数
problem.fun = @(x,D,vital_point)obj_fun(x,D,vital_point); %优化目标函数名称
problem.fun_CV = @(x)obj_fun_CV(x);  %约束条件

%% 模拟退火的参数
SAParameters.temperature = 1000; % 初始温度 设置的足够大的话,可以在初始拥有更好的性能
SAParameters.kb = 0.3; % 温度系数
SAParameters.alpha = 0.99; % 降温系数
SAParameters.penalty = 1.5; % 惩罚系数
SAParameters.num = 1000; % 马尔可夫链长度
SAParameters.Tmin = 1; % 结束温度

第二步:初始解的生成

        在写优化函数时候已经说过,就是将1-20中挑选13个数随机排列。具体实现时可以先将1-20随机排列,然后挑选前13个,代入优化函数中计算出适应度。

%% 解的初始化 
while(1)
    variables = randperm(20);
    variables = variables(1:13);
    variables = variables';  % 初始化一条可行的路径
    amount = 13;
    CV = problem.fun_CV(variables);
    if(CV==0)
        break;
    end
end
var_final = variables; % 初始化最终最优解
T = SAParameters.temperature; % 初始化温度
E0_OBJ = problem.fun(variables,D,vital_point); % 初始化目标函数值
E0_CV = problem.fun_CV(variables); % 初始化CV值
E0 = E0_OBJ+SAParameters.penalty*E0_CV; % 最终目标值
E_OBJ_f = E0; % 初始化最佳温度

第三步:退火过程

交换法产生新解

        每个温度下,都要进行一个马尔科夫链循环的新解适应度的计算。新解产生的方法采用二交换和三交换法,即随机交换两个或三个序列中的值。

%% 通过二交换或三交换产生一个新解
        if (rand < 0.5)	% 随机决定是进行两交换还是三交换
		% 两交换法产生新的解
				ind1 = 0; ind2 = 0;
				while (ind1 == ind2)
					ind1 = ceil(rand.*amount);
					ind2 = ceil(rand.*amount);
				end
				tmp1 = variables(ind1);
				variables(ind1) = variables(ind2);
				variables(ind2) = tmp1; % 随机交换2个变量的位置
		else
		% 三交换法产生新的解
				ind1 = 0; ind2 = 0; ind3 = 0;
				while (ind1 == ind2) || (ind1 == ind3) ...
					|| (ind2 == ind3) || (abs(ind1-ind2) == 1)
					ind1 = ceil(rand.*amount);
					ind2 = ceil(rand.*amount);
					ind3 = ceil(rand.*amount);
				end
				tmp1 = ind1;tmp2 = ind2;tmp3 = ind3;
				% 确保ind1 < ind2 < ind3
                if (ind1 < ind2) && (ind2 < ind3)
            
				elseif (ind1 < ind3) && (ind3 < ind2)
					ind2 = tmp3;ind3 = tmp2;
				elseif (ind2 < ind1) && (ind1 < ind3)
					ind1 = tmp2;ind2 = tmp1;
				elseif (ind2 < ind3) && (ind3 < ind1) 
					ind1 = tmp2;ind2 = tmp3; ind3 = tmp1;
				elseif (ind3 < ind1) && (ind1 < ind2)
					ind1 = tmp3;ind2 = tmp1; ind3 = tmp2;
				elseif (ind3 < ind2) && (ind2 < ind1)
					ind1 = tmp3;ind2 = tmp2; ind3 = tmp1;
                end
				tmplist1 = variables((ind1+1):(ind2-1));
				variables((ind1+1):(ind1+ind3-ind2+1)) = variables((ind2):(ind3));
				variables((ind1+ind3-ind2+2):ind3) = tmplist1;
        end

Metropolis准则淘汰劣解

        计算出新解的适应度后,与原来的解进行比较,倘若比原来小,直接替换;倘若比原来大,基于概率P接受新解。该解的迭代法称为Metropolis准则。

%% 移动后的目标值计算
E_OBJ = problem.fun(variables,D,vital_point); % 移动后的目标函数值
E_CV = problem.fun_CV(variables); % 移动后的CV值
E = E_OBJ+SAParameters.penalty*E_CV;
dE = E-E0;
if (dE<0 && E_CV==0)
    var_final = variables; % 优解迭代
    E_OBJ_f=E_OBJ;
end
prob=exp(-dE/SAParameters.kb/T); % P值计算
if(dE>0 && rand()>prob)
    var_final = variables_temp; % 按P概率接受劣解,否则还原
end

 退火过程总代码如下:

while (T>=SAParameters.Tmin) % 开始降温
    for i = 1:SAParameters.num % 马尔科夫链
        temp_variables = variables;
        %% 通过二交换或三交换产生一个新解
        if (rand < 0.5)	% 随机决定是进行两交换还是三交换
		% 两交换法产生新的解
				ind1 = 0; ind2 = 0;
				while (ind1 == ind2)
					ind1 = ceil(rand.*amount);
					ind2 = ceil(rand.*amount);
				end
				tmp1 = variables(ind1);
				variables(ind1) = variables(ind2);
				variables(ind2) = tmp1; % 随机交换2个变量的位置
		else
		% 三交换法产生新的解
				ind1 = 0; ind2 = 0; ind3 = 0;
				while (ind1 == ind2) || (ind1 == ind3) ...
					|| (ind2 == ind3) || (abs(ind1-ind2) == 1)
					ind1 = ceil(rand.*amount);
					ind2 = ceil(rand.*amount);
					ind3 = ceil(rand.*amount);
				end
				tmp1 = ind1;tmp2 = ind2;tmp3 = ind3;
				% 确保ind1 < ind2 < ind3
                if (ind1 < ind2) && (ind2 < ind3)
            
				elseif (ind1 < ind3) && (ind3 < ind2)
					ind2 = tmp3;ind3 = tmp2;
				elseif (ind2 < ind1) && (ind1 < ind3)
					ind1 = tmp2;ind2 = tmp1;
				elseif (ind2 < ind3) && (ind3 < ind1) 
					ind1 = tmp2;ind2 = tmp3; ind3 = tmp1;
				elseif (ind3 < ind1) && (ind1 < ind2)
					ind1 = tmp3;ind2 = tmp1; ind3 = tmp2;
				elseif (ind3 < ind2) && (ind2 < ind1)
					ind1 = tmp3;ind2 = tmp2; ind3 = tmp1;
                end
				tmplist1 = variables((ind1+1):(ind2-1));
				variables((ind1+1):(ind1+ind3-ind2+1)) = variables((ind2):(ind3));
				variables((ind1+ind3-ind2+2):ind3) = tmplist1;
        end
        %% 移动后的目标值计算
        E_OBJ = problem.fun(variables,D,vital_point); % 移动后的目标函数值
        E_CV = problem.fun_CV(variables); % 移动后的CV值
        E = E_OBJ+SAParameters.penalty*E_CV;
        dE = E-E0;
        if (E_OBJ<=E_OBJ_f && E_CV==0)
           var_final = variables; % 保留新解
           E_OBJ_f=E_OBJ;
        end
        prob=exp(-dE/SAParameters.kb/T);
        if(dE>0 && rand()>prob)
            var_final = variables_temp; % 还原旧解
        end
        E0_OBJ=problem.fun(variables,D,vital_point); %初始目标函数值
        E0_CV=problem.fun_CV(variables); %初始CV值
        E0=E0_OBJ+SAParameters.penalty*E0_CV;
    end
T = T*SAParameters.alpha; % 降温
end

计算结果

        我最后计算出来的最短总距离为1038.75,vital_point对于police_point方案如下:

 

 第一列为交巡警平台节点标号,第二列为对应前往的全市出入口节点标号。

总结

        用智能算法处理整数规划类问题还是比较有意义的。很多连续性问题其实有许多解法,用智能算法往往是大材小用,但是像这种离散类问题,倘若可以用智能算法求解,可以更加灵活,当问题呈几何级数复杂后,也会有时间复杂度和空间复杂度上的优势。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kummunist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值