赞
踩
>> c = [-2;-3;5]; % 等同于 c = [-2,-3,5]'; 求max取相反 >> A = [-2,5,-1;1,3,1]; % 不等式 >> b = [-10;12]; % 不等式 >> Aeq = [1,1,1]; % 等式 >> beq = 7; % 等式 >> [x,fval] = linprog(c,A,b,Aeq,beq,zeros(3,1)); % 得结果 >> x x = 6.4286 0.5714 0 >> z = -fval z = 14.5714 % 说明:在x1 x2 x3 = 6.4286 0.5714 0 的情况下,maxz = 14.5714
例题:
解: 变量替换,化作线性规划模型:
c = 1 2 3 4 >> c = [c,c]' c = 1 2 3 4 1 2 3 4 >> Aeq = [1,-1,-1,1;1,-1,1,-3;1,-1,-2,3] Aeq = 1 -1 -1 1 1 -1 1 -3 1 -1 -2 3 >> Aeq = [Aeq,-Aeq] Aeq = 1 -1 -1 1 -1 1 1 -1 1 -1 1 -3 -1 1 -1 3 1 -1 -2 3 -1 1 2 -3 >> beq = [0;1;-1/2] beq = 0 1.0000 -0.5000 >> [uv,fval] = linprog(c,[],[],Aeq,beq,zeros(8,1)); Optimal solution found. >> x = uv(1:4) - uv(5:end) x = 0.2500 0 0 -0.2500 >> minz = fval minz = 1.2500 >>
整数规划的整数仅仅针对于决策变量而言,与最优解是否为整数无关。
通常,把全部可行解空间反复地分割为越来越小的子
集,称为分枝;并且对每个子集内的解集计算一个目标下界(对于最小值问题),这称
为定界。在每次分枝后,凡是界限超出已知可行解集目标值的那些子集不再进一步分枝,这样,许多子集可不予考虑,这称剪枝。这就是分枝定界法的主要思路。
分枝定界法可用于解纯整数或混合的整数规划问题。
>> c = [-3;-2]; >> A = [2,3;2,1]; >> b = [14;9]; >> [x,fval] = linprog(c,A,b,[],[],zeros(2,1)); Optimal solution found. >> x x = 3.2500 2.5000 >> z = - fval z = 14.7500 >>
可以看到,x并不是整数,下面做分支定界:
>> [x,fval] = linprog(c,A,b,[],[],zeros(2,1),[3,inf]); Optimal solution found. >> x x = 3.0000 2.6667 >> z = -fval z = 14.3333 >>
继续做分支定界:
>> [x,fval] = linprog(c,A,b,[],[],[4,0]); Optimal solution found. >> x x = 4.0000 1.0000 >> z = -fval z = 14.0000
14.3333比14.0000大,所以在x1≤3下再做分支定界:
>> [x,fval] = linprog(c,A,b,[],[],zeros(2,1),[3,2]); Optimal solution found. >> x x = 3 2 >> z = -fval z = 13 >>
继续分支定界:
>> [x,fval] = linprog(c,A,b,[],[],[0,3],[3,inf]); Optimal solution found. >> x x = 2.5000 3.0000 >> z = -fval z = 13.5000 >>
所以整数规划的最优解为14。
branchbound.m
function [newx,newfval,status,newbound] = branchbound(f,A,B,I,x,fval,bound,Aeq,Beq,lb,ub,e) % 分支定界法求解整数规划 % f,A,B,Aeq,Beq,lb,ub与线性规划相同 % I为整数限制变量的向量 % x为初始解,fval为初始值 options = optimset('display','off'); [x0,fval0,status0]=linprog(f,A,B,Aeq,Beq,lb,ub,[],options); %递归中的最终退出条件 %无解或者解比现有上界大则返回原解 if status0 <= 0 || fval0 >= bound newx = x; newfval = fval; newbound = bound; status = status0; return; end %是否为整数解,如果是整数解则返回 intindex = find(abs(x0(I) - round(x0(I))) > e); if isempty(intindex) %判断是否为空值 newx(I) = round(x0(I)); newfval = fval0; newbound = fval0; status = 1; return; end %当有非整可行解时,则进行分支求解 %此时必定会有整数解或空解 %找到第一个不满足整数要求的变量 n = I(intindex(1)); addA = zeros(1,length(f)); addA(n) = 1; %构造第一个分支 x<=floor(x(n)) A = [A;addA]; B = [B,floor(x(n))];%向下取整 [x1,fval1,status1,bound1] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e); A(end,:) = []; B(:,end) = []; %解得第一个分支,若为更优解则替换,若不是则保持原状 status = status1; if status1 > 0 && bound1 < bound newx = x1; newfval = fval1; bound = fval1; newbound = bound1; else newx = x0; newfval = fval0; newbound = bound; end %构造第二分支 A = [A;-addA]; B = [B,-ceil(x(n))];%向上取整 [x2,fval2,status2,bound2] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e); A(end,:) = []; B(:,end) = []; %解得第二分支,并与第一分支做比较,如果更优则替换 if status2 > 0 && bound2 < bound status = status2; newx = x2; newfval = fval2; newbound = bound2; end
intprog.m
function [x,fval,status] = intprog(f,A,B,I,Aeq,Beq,lb,ub,e) %整数规划求解函数 intprog() % 其中 f为目标函数向量 % A和B为不等式约束 Aeq与Beq为等式约束 % I为整数约束 % lb与ub分别为变量下界与上界 % x为最优解,fval为最优值 %例子: % maximize 20 x1 + 10 x2 % S.T. % 5 x1 + 4 x2 <=24 % 2 x1 + 5 x2 <=13 % x1, x2 >=0 % x1, x2是整数 % f=[-20, -10]; % A=[ 5 4; 2 5]; % B=[24; 13]; % lb=[0 0]; % ub=[inf inf]; % I=[1,2]; % e=0.000001; % [x v s]= IP(f,A,B,I,[],[],lb,ub,,e) % x = 4 1 v = -90.0000 s = 1 % 控制输入参数 if nargin < 9, e = 0.00001; if nargin < 8, ub = []; if nargin < 7, lb = []; if nargin < 6, Beq = []; if nargin < 5, Aeq = []; if nargin < 4, I = [1:length(f)]; end, end, end, end, end, end %求解整数规划对应的线性规划,判断是否有解 options = optimset('display','off'); [x0,fval0,exitflag] = linprog(f,A,B,Aeq,Beq,lb,ub,[],options); if exitflag < 0 disp('没有合适整数解'); x = x0; fval = fval0; status = exitflag; return; else %采用分支定界法求解 bound = inf; [x,fval,status] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e); end
分支定界流程:
>> c = [-40;-90]; >> A = [9,7;7,20]; >> b = [56;70]; >> [x,fval] = intlinprog(c,[1 2],A,b,[],[],zeros(2,1)); >> x x = 4.0000 2.0000 >> -fval ans = 340
x = intlinprog(f,intcon,A,b,Aeq,beq,lb,ub)
:函数相比linprog多了一个参数intcon,用于标定整数变量的位置:x1、x2为整数,即intcon = [1 2]。
解:两个不等式,这里引入两个松弛变量x3和x4;
function [intx,intf] = DividePlane(A,c,b,baseVector) %功能:用割平面法求解整数规划 %调用格式:[intx,intf]=DividePlane(A,c,b,baseVector) %其中, A:约束矩阵; % c:目标函数系数向量; % b:约束右端向量; % baseVector:初始基向量; % intx:目标函数取最值时的自变量值; % intf:目标函数的最值; sz = size(A); nVia = sz(2);%获取有多少决策变量 n = sz(1);%获取有多少约束条件 xx = 1:nVia; if length(baseVector) ~= n disp('基变量的个数要与约束矩阵的行数相等!'); mx = NaN; mf = NaN; return; end M = 0; sigma = -[transpose(c) zeros(1,(nVia-length(c)))]; xb = b; %首先用单纯形法求出最优解 while 1 [maxs,ind] = max(sigma); %--------------------用单纯形法求最优解-------------------------------------- if maxs <= 0 %当检验数均小于0时,求得最优解。 vr = find(c~=0 ,1,'last'); for l=1:vr ele = find(baseVector == l,1); if(isempty(ele)) mx(l) = 0; else mx(l)=xb(ele); end end if max(abs(round(mx) - mx))<1.0e-7 %判断最优解是否为整数解,如果是整数解。 intx = mx; intf = mx*c; return; else %如果最优解不是整数解时,构建切割方程 sz = size(A); sr = sz(1); sc = sz(2); [max_x, index_x] = max(abs(round(mx) - mx)); [isB, num] = find(index_x == baseVector); fi = xb(num) - floor(xb(num)); for i=1:(index_x-1) Atmp(1,i) = A(num,i) - floor(A(num,i)); end for i=(index_x+1):sc Atmp(1,i) = A(num,i) - floor(A(num,i)); end Atmp(1,index_x) = 0; %构建对偶单纯形法的初始表格 A = [A zeros(sr,1);-Atmp(1,:) 1]; xb = [xb;-fi]; baseVector = [baseVector sc+1]; sigma = [sigma 0]; %-------------------对偶单纯形法的迭代过程---------------------- while 1 %---------------------------------------------------------- if xb >= 0 %判断如果右端向量均大于0,求得最优解 if max(abs(round(xb) - xb))<1.0e-7 %如果用对偶单纯形法求得了整数解,则返回最优整数解 vr = find(c~=0 ,1,'last'); for l=1:vr ele = find(baseVector == l,1); if(isempty(ele)) mx_1(l) = 0; else mx_1(l)=xb(ele); end end intx = mx_1; intf = mx_1*c; return; else %如果对偶单纯形法求得的最优解不是整数解,继续添加切割方程 sz = size(A); sr = sz(1); sc = sz(2); [max_x, index_x] = max(abs(round(mx_1) - mx_1)); [isB, num] = find(index_x == baseVector); fi = xb(num) - floor(xb(num)); for i=1:(index_x-1) Atmp(1,i) = A(num,i) - floor(A(num,i)); end for i=(index_x+1):sc Atmp(1,i) = A(num,i) - floor(A(num,i)); end Atmp(1,index_x) = 0; %下一次对偶单纯形迭代的初始表格 A = [A zeros(sr,1);-Atmp(1,:) 1]; xb = [xb;-fi]; baseVector = [baseVector sc+1]; sigma = [sigma 0]; continue; end else %如果右端向量不全大于0,则进行对偶单纯形法的换基变量过程 minb_1 = inf; chagB_1 = inf; sA = size(A); [br,idb] = min(xb); for j=1:sA(2) if A(idb,j)<0 bm = sigma(j)/A(idb,j); if bm<minb_1 minb_1 = bm; chagB_1 = j; end end end sigma = sigma -A(idb,:)*minb_1; xb(idb) = xb(idb)/A(idb,chagB_1); A(idb,:) = A(idb,:)/A(idb,chagB_1); for i =1:sA(1) if i ~= idb xb(i) = xb(i)-A(i,chagB_1)*xb(idb); A(i,:) = A(i,:) - A(i,chagB_1)*A(idb,:); end end baseVector(idb) = chagB_1; end %------------------------------------------------------------ end %--------------------对偶单纯形法的迭代过程--------------------- end else %如果检验数有不小于0的,则进行单纯形算法的迭代过程 minb = inf; chagB = inf; for j=1:n if A(j,ind)>0 bz = xb(j)/A(j,ind); if bz<minb minb = bz; chagB = j; end end end sigma = sigma -A(chagB,:)*maxs/A(chagB,ind); xb(chagB) = xb(chagB)/A(chagB,ind); A(chagB,:) = A(chagB,:)/A(chagB,ind); for i =1:n if i ~= chagB xb(i) = xb(i)-A(i,ind)*xb(chagB); A(i,:) = A(i,:) - A(i,ind)*A(chagB,:); end end baseVector(chagB) = ind; end M = M + 1; if (M == 1000000) disp('找不到最优解!'); mx = NaN; minf = NaN; return; end end
>> c = [-1;-1]; % 不要加松弛变量 >> A = [-1 1 1 0;3 1 0 1]; % 加上松弛变量 >> b = [1;4]; >> [x fval] = DividePlane(A,c,b,[3 4]); % 松弛变量 3 4 >> x x = 1.0000 1.0000 >> maxz = -fval maxz = 2 >>
0-1规划问题也可以看做区间在[0,1]的整数规划,下面利用intlinprog函数进行计算:
>> c = [-3 2 -5]'; >> A = [1 2 -1;1 4 1]; >> b = [2;4]; >> c = [-3 2 -5]'; >> A = [1 2 -1;1 4 1;1 1 0;0 4 1]; >> b = [2;4;3;6]; >> [x fval] = intlinprog(c,[1 2 3],A,b,[],[],zeros(3,1),ones(3,1)); >> x x = 1 0 1 >> maxz = -fval maxz = 8 >>
匈牙利算法解决0-1规划问题:
举例
每一行找出最小值让该行各个元素减去最小值,每一列找出最小值让该列各个元素减去最小值,从只有一个0元素的行开始,将0元素圈圈,划掉该0元素所在列的其他0元素,接着再找只有一个0元素的行,重复操作,当行中0元素没有一个的时候,找只有一个0元素的列,圈圈,划掉该0元素所在行的其他0元素。
最后,若圈出的0元素的个数小于阶数n,进行如下操作:(否则找到解)
对没有圈0元素的行打√,对打√号的行中的所有划掉0元素的所在列打√,对打√的列中含圈0元素的所在行打√,重复上述3步,直到得不出新的打√号的行列为止。
下面,对没有打√的行画横线,对打√的列画纵线,从而得到覆盖所有0元素的最少横线数,应当等于圈0元素的个数,然后进行如下操作,变换当前矩阵来增加0元素,以便找到n个独立0元素:
找到没有被直线覆盖的所有元素中的最小元素值,将打√的各行减去最小元素值,打√的各列加上最小元素值,从而得到一个新的指派矩阵,用这个新的指派矩阵重复上述所有步骤,直到找出n个独立0元素结果为止。
例题
实现步骤
>> c = [3 8 2 10 3;8 7 2 9 7;6 4 2 7 5;8 4 2 3 5;9 10 6 9 10] c = 3 8 2 10 3 8 7 2 9 7 6 4 2 7 5 8 4 2 3 5 9 10 6 9 10 >> c = c(:); % 矩阵转换为向量 >> a = zeros(10,25); >> for i = 1:5 a(i,(i-1)*5+1:5*i) = 1; a(5+i,i:5:25) = 1; end % 循环将指派问题转换为线性规划问题 >> b = ones(10,1); % 10个约束(5*2) >> [x y] = linprog(c,[],[],a,b,zeros(25,1),ones(25,1)); Optimal solution found. >> X = reshape(x,5,5) X = 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 >> opt = y opt = 21 >>
>> [x y] = linprog(-c,[],[],a,b,zeros(25,1),ones(25,1)); Optimal solution found. >> X = reshape(x,5,5) X = 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 >> opt = -y opt = 37 >>
>> c = [6 7 11 2;4 5 9 8;3 1 10 4;5 9 8 2]; >> a = zeros(8,16); >> for i = 1:4 a(i,(i-1)*4+1:4*i) = 1; a(4+i,i:4:16) = 1; end >> b = ones(8,1); >> [x y] = linprog(c,[],[],a,b,zeros(16,1),ones(16,1)); Optimal solution found. >> X = reshape(x,4,4) X = 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 >> opt = y opt = 15 >>
>> [x y]= linprog(-c,[],[],a,b,zeros(25,1),ones(25,1)); Optimal solution found. >> X = reshape(x,5,5) X = 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 >> opt = -y opt = 37 >>
>> c = [6 7 11 2;4 5 9 8;3 1 10 4;5 9 8 2]; >> a = zeros(8,16); >> for i = 1:4 a(i,(i-1)*4+1:4*i) = 1; a(4+i,i:4:16) = 1; end >> b = ones(8,1); >> [x y] = linprog(c,[],[],a,b,zeros(16,1),ones(16,1)); Optimal solution found. >> X = reshape(x,4,4) X = 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 >> opt = y opt = 15 >>
《数学建模算法与应用》(司守奎)
《数学建模算法与应用习题解答》(司守奎)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。