一.线性规划
1.单纯形法求解
% [x fval] = linprog(c, A, b, Aeq, beq, lb,ub, x0)
% c是目标函数的系数向量,目标函数向量是列向量,A是不等式约束Ax<=b的系数矩阵,b是不等式约束Ax<=b的常数项
% Aeq是等式约束Aeq x=beq的系数矩阵,beq是等式约束Aeq x=beq的常数项
% lb是X的下限,ub是X的上限,X是向量[x1,x2,...xn]' , 即决策变量。
% 迭代的初始值为x0(单纯形法初始值一般不用给
例题:
%% 生产决策问题
format long g %可以将Matlab的计算结果显示为一般的长数字格式(默认会保留四位小数,或使用科学计数法)
% (1) 系数向量(列向量)
c = zeros(9,1); % 初始化目标函数的系数向量全为0
c(1) = 1.25 -0.25 -300/6000*5; % x1前面的系数是c1
c(2) = 1.25 -0.25 -321/10000*7;
c(3) = -250 / 4000 * 6;
c(4) = -783/7000*4;
c(5) = -200/4000 * 7;
c(6) = -300/6000*10;
c(7) = -321 / 10000 * 9;
c(8) = 2-0.35-250/4000*8;
c(9) = 2.8-0.5-321/10000*12-783/7000*11;
c = -c; % 我们求的是最大值,所以这里需要改变符号
% (2) 不等式约束
A = zeros(5,9);
A(1,1) = 5; A(1,6) = 10;
A(2,2) = 7; A(2,7) = 9; A(2,9) = 12;
A(3,3) = 6; A(3,8) = 8;
A(4,4) = 4; A(4,9) = 11;
A(5,5) = 7;
b = [6000 10000 4000 7000 4000]';
% (3) 等式约束
Aeq = [1 1 -1 -1 -1 0 0 0 0;
0 0 0 0 0 1 1 -1 0];
beq = [0 0]';
%(4)上下界
lb = zeros(9,1);
% 进行求解
[x fval] = linprog(c, A, b, Aeq, beq, lb)
fval = -fval
二.整数规划
1.线性整数规划
[x,fval]=intlinprog(f,xint,A,b,Aeq,beq,lb,ub)
%xint表示哪些量是整数变量
例题:
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)
2.0-1规划
仍然使用intlinprog函数,不过lb,ub范围【0,1】即可
lb = zeros(10,1); % 约束变量的范围下限
ub = ones(10,1); % 约束变量的范围上限
%最后调用intlinprog()函数
[x,fval]=intlinprog(c,intcon,A,b,Aeq,beq,lb,ub)
0-1规划例题:(或者利用动态规划解题)
(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)指派问题
%% 指派问题(选择队员去进行游泳接力比赛)
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)钢管切割问题
%% 钢管切割问题
%% (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% 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)
三.非线性规划
1.说明
(1)非线性规划求解出的是局部最优解,初始值选取很重要。
(2)如果求“全局最优解”:先用蒙特卡洛模拟,得到一个初始解,然后将这个解作为初始值来求最优解。
(3)option选项可以给定求解的算法,有四种:内点法,序列二次规划法,有效集法,信頼域反射算法。
(4)注意:目标函数向量行列方向取决于初始值X0的行列方向(不一定必须是列向量)
(5)不同算法有各自的优缺点和适用情况,可以改变求解的算法来看求解的结果是否变好了(可以体现稳健性)
% %% 非线性规划的函数
% [x,fval] = fmincon(@fun,x0,A,b,Aeq,beq,lb,ub,@nonlfun,option)
% x0表示给定的初始值(用行向量或者列向量表示),必须得写
% A b表示线性不等式约束
% Aeq beq 表示线性等式约束
% lb ub 表示上下界约束
% @fun表示目标函数
% @nonlfun表示非线性约束的函数
% option 表示求解非线性规划使用的方
2.Matlab相关操作
%% 例题1的求解
% max f(x) = x1^2 +x2^2 -x1*x2 -2x1 -5x2
% s.t. -(x1-1)^2 +x2 >= 0 ; 2x1-3x2+6 >= 0
x0 = [0 0]; %任意给定一个初始值
A = [-2 3]; b = 6;
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1) % 注意 fun1.m文件和nonlfun1.m文件都必须在当前文件夹目录下
fval = -fval
function f = fun1(x)
% max f(x) = x1^2 +x2^2 -x1*x2 -2x1 -5x2
f = -x(1)^2-x(2)^2 +x(1)*x(2)+2*x(1)+5*x(2) ;
end
function [c,ceq] = nonlfun1(x)
% -(x1-1)^2 +x2 >= 0
c = [(x(1)-1)^2-x(2)]; % 千万別写成了: (x1-1)^2 -x2
ceq = []; % 不存在非线性等式约束,所以用[]表示
end
% 使用interior point算法 (内点法)
option = optimoptions('fmincon','Algorithm','interior-point')
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
fval = -fval
% 使用SQP算法 (序列二次规划法)
option = optimoptions('fmincon','Algorithm','sqp')
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
fval = -fval %得到-4.358,远远大于内点法得到的-1,猜想是初始值的影响
% 改变初始值试试
x0 = [1 1]; %任意给定一个初始值
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option) % 最小值为-1,和内点法相同(这说明内点法的适应性要好)
fval = -fval
% 使用active set算法 (有效集法)
option = optimoptions('fmincon','Algorithm','active-set')
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
fval = -fval
% 使用trust region reflective (信赖域反射算法)
option = optimoptions('fmincon','Algorithm','trust-region-reflective')
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1,option)
fval = -fval
% this algorithm does not solve problems with the constraints you have specified.
% 这说明这个算法不适用我们这个约束条件,所以以后遇到了不能求解的情况,记得更换其他算法试
%% 使用蒙特卡罗的方法来找初始值
clc,clear;
n=10000000; %生成的随机数组数
x1=unifrnd(-100,100,n,1); % 生成在[-100,100]之间均匀分布的随机数组成的n行1列的向量构成x1
x2=unifrnd(-100,100,n,1); % 生成在[-100,100]之间均匀分布的随机数组成的n行1列的向量构成x2
fmin=+inf; % 初始化函数f的最小值为正无穷(后续只要找到一个比它小的我们就对其更新)
for i=1:n
x = [x1(i), x2(i)]; %构造x向量, 这里千万别写成了:x =[x1, x2]
if ((x(1)-1)^2-x(2)<=0) & (-2*x(1)+3*x(2)-6 <= 0) % 判断是否满足条件
result = -x(1)^2-x(2)^2 +x(1)*x(2)+2*x(1)+5*x(2) ; % 如果满足条件就计算函数值
if result < fmin % 如果这个函数值小于我们之前计算出来的最小值
fmin = result; % 那么就更新这个函数值为新的最小值
x0 = x; % 并且将此时的x1 x2更新为初始值
end
end
end
disp('蒙特卡罗选取的初始值为:'); disp(x0)
A = [-2 3]; b = 6;
[x,fval] = fmincon(@fun1,x0,A,b,[],[],[],[],@nonlfun1)
fval = -fval
3.典型例题
(1)选址问题
%% 选址问题
clear;clc
format long g
% % (1) 系数向量
% a=[1.25 8.75 0.5 5.75 3 7.25]; % 工地的横坐标
% b=[1.25 0.75 4.75 5 6.5 7.25]; % 工地的纵坐标
% x = [5 2]; % 料场的横坐标
% y = [1 7]; % 料场的纵坐标
% c = []; % 初始化用来保存工地和料场距离的向量 (这个向量就是我们的系数向量)
% for j =1:2
% for i = 1:6
% c = [c; sqrt( (a(i)-x(j))^2 + (b(i)-y(j))^2)]; % 每循环一次就在c的末尾插入新的元素
% end
% end
% (2) 不等式约束
A =zeros(2,16);
A(1,1:6) = 1;
A(2,7:12) = 1;
b = [20,20]';
% (3) 等式约束
Aeq = zeros(6,16);
for i = 1:6
Aeq(i,i) = 1; Aeq(i,i+6) = 1;
end
beq = [3 5 4 7 6 11]'; % 每个工地的日需求量
%(4)上下界
lb = zeros(16,1);
% lb = [zeros(12,1); -inf*ones(4,1)]; 两个新料场坐标的下界可以设为-inf
% 进行求解
x0 = [3 5 0 7 0 1 0 0 4 0 6 10 5 1 2 7]; % 用第一问的结果作为初始值
[x,fval] = fmincon(@fun5,x0,A,b,Aeq,beq,lb)
reshape(x(1:12),6,2) % 将x的前12个元素变为6行2列便于观察(reshape函数是按照列的顺序进行转换的,也就是第一列读完,读第二列,即x1对应x_1,1,x2对应x_2,1)
function f = fun5(xx) %为了避免和下面的x同把决策变量的向量符号用xx表
a=[1.25 8.75 0.5 5.75 3 7.25]; % 工地的横坐标
b=[1.25 0.75 4.75 5 6.5 7.25]; % 工地的纵坐标
x = [xx(13) xx(15)]; % 新料场的横坐标
y = [xx(14) xx(16)]; % 新料场的纵坐标
c = []; % 初始化用来保存工地和料场距离的向量 (这个向量就是我们的系数向量)
for j =1:2
for i = 1:6
c = [c; sqrt( (a(i)-x(j))^2 + (b(i)-y(j))^2)]; % 每循环一次就在c的末尾插入新的元素
end
end
% 下面我们要求吨千米数,注意c是列向量,我们计算非线性规划时给定的初始值x0是行向量
f = xx(1:12) * c;
end
四.最大最小化模型
1.模型一般形式
求最大值的最小化问题,即在最不利的情况下寻求最优的策略
2.例题
x0 = [6, 6]; % 给定初始值
lb = [3, 4]; % 决策变量的下界
ub = [8, 10]; % 决策变量的上界
[x,feval] = fminimax(@Fun,x0,[],[],[],[],lb,ub)
max(feval)
function f = Fun(x)
a=[1 4 3 5 9 12 6 20 17 8];
b=[2 10 8 18 1 4 5 10 8 9];
% 函数向量
f=zeros(10,1); %初始化
for i = 1:10
f(i) = abs(x(1)-a(i))+abs(x(2)-b(i));
end
end