一.整数规划
接着来看数学规划模型类型中的整数规划。
总的来说,整数规划可以分为两类,一类是线性整数规划,另一类是非线性整数规划。
其中,可以用matlab轻易求解的是线性整数规划,其实就是再线性规划的基础上,再加上一个整数约束的条件,规定决策变量要取整数,而在生活中的许多实际问题中都是这样要求的。另一类是非线性整数规划,由于非线性规划只要求约束条件和目标函数中有一个是非线性表达式即可,所以非线性整数规划的类型特别多,我们不能用任何一种常用的算法可以解决问题。我们在matlab中求解的主要是线性整数规划求解。
同样的,我们用matlab求解线性整数规划时,要先把问题转换成matlab可以理解的标准形式,同线性规划的标准型类似。求解线性规划的函数是linprog(),而求解线性整数规划的函数是intlinprog(),相比前者,后者多了intcon这个参数,用来指定哪些决策变量是整数,但是不能指定初始值。但在我们求解线性规划的问题时,我们也很少设置初始值,因为matlab求解线性规划的算法是单纯形法,所以最终一定可以得出一个解,而加上初始值,只是让matlab求解的速度更快了些。
在线性整数规划中,有一种很特殊的整数规划,叫做0-1规划,matlab也可以用来求解这种整数规划。
可以看出,求解0-1规划时,只是在上约束和下约束条件中多做了一些文章而已。
想必这些例题可以很容易的解决了,但在求解时一定要先转换成标准型才可以,如求解最大值时一定要转换成求解最小值问题。
给出这几道例题的代码可以更容易地理解。
%% 线性整数规划问题
%% 例1
c=[-20,-10]';
intcon=[1,2]; % x1和x2限定为整数
A=[5,4;
2,5];
b=[24;13];
lb=zeros(2,1);
[x,fval]=intlinprog(c,intcon,A,b,[],[],lb)
fval = -fval
%% 例2
c=[18,23,5]';
intcon=3; % x3限定为整数
A=[107,500,0;
72,121,65;
-107,-500,0;
-72,-121,-65];
b=[50000;2250;-500;-2000];
lb=zeros(3,1);
[x,fval]=intlinprog(c,intcon,A,b,[],[],lb)
%% 例3
c=[-3;-2;-1]; intcon=3; % x3限定为整数
A=ones(1,3); b=7;
Aeq=[4 2 1]; beq=12;
lb=zeros(3,1); ub=[+inf;+inf;1]; %x(3)为0-1变量
[x,fval]=intlinprog(c,intcon,A,b,Aeq,beq,lb,ub)
二.整数规划的典型例题
(1).背包问题
这是一道很经典的线性整数规划的问题,同时这也是一道0-1规划。直接附上解析和代码。
%% 背包问题(货车运送货物的问题)
c = -[540 200 180 350 60 150 280 450 320 120]; % 目标函数的系数矩阵(最大化问题记得加负号)
intcon=[1:10]; % 整数变量的位置(一共10个决策变量,均为0-1整数变量)
A = [6 3 4 5 1 2 3 5 4 2]; b = 30; % 线性不等式约束的系数矩阵和常数项向量(物品的重量不能超过30)
Aeq = []; beq =[]; % 不存在线性等式约束
lb = zeros(10,1); % 约束变量的范围下限
ub = ones(10,1); % 约束变量的范围上限
%最后调用intlinprog()函数
[x,fval]=intlinprog(c,intcon,A,b,Aeq,beq,lb,ub)
fval = -fval
(2).指派问题
首先一共在5位队员里选择4名队员参加混合泳接力,所以有1名队员我们要把他踢出去,其次,每位队员所擅长的项目都不同,而且一种项目只能由一个队员参加,我们要从中确定最优的方案使我们最终混合泳的时间花费最少。
直接附上我们的解析。
可以看出本题我们使用了双下标的决策变量,和线性规划中的投料问题很类似。给出我们的目标函数和约束条件。
目标函数很容易理解,一名队员只能选择参加一种泳姿,若参加的话,我们就让对应的Xij为1。对于约束条件1,每个人只能入选4种泳姿之一,例如X11表示甲队员参加第1种泳姿,所以甲队员不能再选择其他泳姿,于是X11+X12+X13+X14应该小于等于1,小于1是可能甲队员被我们踢出去了,他可能一个泳姿都没参加。对于约束条件2,每种泳姿有且仅有1人参加,所以X11+X21+X31+X41一定会等于1。
同时,由于本题 使用了双下标的决策变量,再转换成matlab的标准型时,我们要把双下标的决策变量转换成单下标的决策变量。
附上求解的代码。
%% 指派问题(选择队员去进行游泳接力比赛)
clear;clc
c = [66.8 75.6 87 58.6 57.2 66 66.4 53 78 67.8 84.6 59.4 70 74.2 69.6 57.2 67.4 71 83.8 62.4]'; % 目标函数的系数矩阵(先列后行的写法)
intcon = [1:20]; % 整数变量的位置(一共20个决策变量,均为0-1整数变量)
% 线性不等式约束的系数矩阵和常数项向量(每个人只能入选四种泳姿之一,一共五个约束)
A = [1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1];
% A = zeros(5,20);
% for i = 1:5
% A(i, (4*i-3): 4*i) = 1;
% end
b = [1;1;1;1;1];
% 线性等式约束的系数矩阵和常数项向量 (每种泳姿有且仅有一人参加,一共四个约束)
Aeq = [1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0;
0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0;
0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0;
0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1];
% Aeq = [eye(4),eye(4),eye(4),eye(4),eye(4)]; % 或者写成 repmat(eye(4),1,5)
beq = [1;1;1;1];
lb = zeros(20,1); % 约束变量的范围下限
ub = ones(20,1); % 约束变量的范围上限
%最后调用intlinprog()函数
[x,fval] = intlinprog(c,intcon,A,b,Aeq,beq,lb,ub)
% reshape(x,4,5)'
% 0 0 0 1 甲自由泳
% 1 0 0 0 乙蝶泳
% 0 1 0 0 丙仰泳
% 0 0 1 0 丁蛙泳
% 0 0 0 0 戊不参加
(3).钢管切割问题
如问题所示,我们需要钢架长2.9m、2.1m和1m的圆钢各100根,求如何切割材料可以使用的原材料最少。
我们不妨猜测,如果我们每根6.9m的原料都只用来切割这三种圆钢各一根,可以发现,每根原材料都会剩下0.9m的料头,这样会大大浪费我们的原材料,所以我们应该把这0.9m的料头也利用起来,如果我们能把两根原材料切割剩下的0.9m的原材料接到一起,那么我们就得到了一根1.8m的原材料,就可以用来切割长1m的圆钢了。
我们来看分析,可以看到分析为我们列出来了7种可行的切割方法,每种切割方法所最终剩下的料头长度都小于等于0.9m。在实际中,我们可以混合使用这七种切割方法。这样就得到了我们的决策变量。
我们的目标函数就是要求出所需要的使用最小的原材料数量。分别看我们的三个不等式约束条件。由于我们最终需要三种圆钢各100根,所以我们最终得到的三种圆钢的数量应大于或等于100根。以2.9m的圆钢为例,方案A可以得到1根2.9m的圆钢,方案B可以得到2根2.9m的圆钢,方案G可以得到1根2.9m的圆钢。所以,最终我们得到的2.9m的圆钢数量应该是X1+2X2+X7,这样就得出了我们的第一个不等式约束条件。其他雷同。
%% 钢管切割问题
%% (1)枚举法找出同一个原材料上所有的切割方法
for i = 0: 2 % 2.9m长的圆钢的数量
for j = 0: 3 % 2.1m长的圆钢的数量
for k = 0:6 % 1m长的圆钢的数量
if 2.9*i+2.1*j+1*k >= 6 && 2.9*i+2.1*j+1*k <= 6.9
disp([i, j, k])
end
end
end
end
% 有同学使用比较老的MATLAB版本,会出现浮点数计算的误差
% 只需要将上面的if这一行进行适当的放缩即可。
% if 2.9*i+2.1*j+1*k >= 6-0.0000001 && 2.9*i+2.1*j+1*k <= 6.9+0.0000001
% 有兴趣的同学可以百度下:浮点数计算误差
%% (2) 线性整数规划问题的求解
c = ones(7,1); % 目标函数的系数矩阵
intcon=[1:7]; % 整数变量的位置(一共7个决策变量,均为整数变量)
A = -[1 2 0 0 0 0 1;
0 0 3 2 1 0 1;
4 1 0 2 4 6 1]; % 线性不等式约束的系数矩阵
b = -[100 100 100]'; % 线性不等式约束的常数项向量
lb = zeros(7,1); % 约束变量的范围下限
[x,fval]=intlinprog(c,intcon,A,b,[],[],lb)