当前位置:   article > 正文

数学建模(三)整数规划

整数规划

视频推荐:B站_数学建模老哥

目录

一、整数规划基本原理

1.1 整数规划的分类

1.2 整数规划的特点

1.3 案例

1.4  整数规划的数学模型一般形式

二、整数线性规划的求解方法

2.1 分枝定界法

2.1.1 分枝定界法的求解过程

2.1.2 案例

2.1.3 代码实现

2.2 割平面法

2.2.1 割平面法的基本思想

2.2.2 割平面法的基本步骤

2.2.3 案例和代码实现


一、整数规划基本原理

数学规划中的变量(部分或全部)限制为整数时,称为整数规划。若在线性规划模型中,变量限制为整数,则称为整数线性规划。目前所流行的求解整数规划的方法,往往只适用于整数线性规划。目前还没有一种方法能有效地求解一切整数规划。

1.1 整数规划的分类

(1)变量全限制为整数时,称为纯(完全)整数规划。

(2)变量部分限制为整数的,称为混合整数规划

(3)变量取值要么为0要么为1,称为0-1规划。

1.2 整数规划的特点

1. 原线性规划有最优解,当自变量限制为整数后,其整数规划解出现下述情况:

    (1)原线性规划最优解全是整数,则整数规划最优解与线性规划最优解一致

    (2)整数规划可能不存在可行解

    (3)有可行解(当然就存在最优解),但最优解值变差。

2. 整数规划最优解不能按照实数最优解简单取整而获得

1.3 案例

合理下料问题:

设用某型号的圆钢下零件A1,A2...,Am的毛坯。在一根圆钢上下料的方式有B1,B2,... Bn种,每种下料方式可以得到各种零件的毛坯数以及每种零件的需要量,如表所示。问怎样安排下料方式,使得即满足需要,所用的原材料又最少?

如表所示:

 模型

其中,xj表示用Bj种方式下料根数,aij为每种下料方式可以得到各种零件的毛坯数,bi每种零件的需要量

1.4  整数规划的数学模型一般形式

另外补充: 整数规划与松弛的线性规划之间的关系。

不难看出两者之间的关系。

二、整数线性规划的求解方法

        从数学模型上看整数规划似乎是线性规划的一种特殊形式,求解只需在线性规划的基础上,通过舍入取整,寻求满足整数要求的解即可。但实际上两者却有很大的不同,通过舍入得到的解(整数)也不一定就是最优解,有时甚至不能保证所得到的解是整数可行解

2.1 分枝定界法

分枝定界法(branch and bound)是一种求解整数规划问题的最常用算法。分支定界法是一种搜索与迭代的方法,选择不同的分支变量和子问题进行分支。

2.1.1 分枝定界法的求解过程

  • 1. 先求出相应松弛问题最优解
  • 2. 若松弛问题无可行解,则整数线性规划问题无可行解
  • 3. 若求得的松弛问题最优解符合整数要求,则是整数线性规划问题的最优解。若不满足整数条件,则任选一个不满足整数条件的变量 xi0 来构造新的约束,分别添加到松弛问题中形成两个子问题
  •                                                       xi[xi0]xi[xi0]+1
  • 依次在缩小的可行域中求解新构造的线性规划的最优解,并重复上述过程,直到子问题无解或有整数最优解(被查清)。

Q:为什么在步骤3中不满足整数条件时要添加上述两个约束条件?

A:因为变量 xi0是一个不满足整数条件的变量,它注定无法构成整数规划的最优解,因此我们要向变量 xi0的两边去寻找合适的整数最优解。

注意:构造新的约束条件是分别到整数规划问题对应的松弛问题中,独立构成两个不同的子问题再求解。

详情参考:分枝定界法

2.1.2 案例

分枝定界法总体上有点像二叉树,能看懂下面的案例基本就能理解分枝定界法。

2.1.3 代码实现

数学模型如下:

1. 先创建intprog.m文件:

  1. function [x,fval,status] = intprog(f,A,B,I,Aeq,Beq,lb,ub,e)
  2. %整数规划求解函数 intprog()
  3. % 其中 f为目标函数向量
  4. % A和B为不等式约束 Aeq与Beq为等式约束
  5. % I为整数约束
  6. % lb与ub分别为变量下界与上界
  7. % x为最优解,fval为最优值
  8. %例子:
  9. % maximize 20 x1 + 10 x2
  10. % S.T.
  11. % 5 x1 + 4 x2 <=24
  12. % 2 x1 + 5 x2 <=13
  13. % x1, x2 >=0
  14. % x1, x2是整数
  15. % f=[-20, -10];
  16. % A=[ 5 4; 2 5];
  17. % B=[24; 13];
  18. % lb=[0 0];
  19. % ub=[inf inf];
  20. % I=[1,2];
  21. % e=0.000001;
  22. % [x v s]= IP(f,A,B,I,[],[],lb,ub,,e)
  23. % x = 4 1 v = -90.0000 s = 1
  24. % 控制输入参数
  25. if nargin < 9, e = 0.00001;
  26. if nargin < 8, ub = [];
  27. if nargin < 7, lb = [];
  28. if nargin < 6, Beq = [];
  29. if nargin < 5, Aeq = [];
  30. if nargin < 4, I = [1:length(f)];
  31. end, end, end, end, end, end
  32. %求解整数规划对应的线性规划,判断是否有解
  33. options = optimset('display','off'); %不需要每次优化结果都输出
  34. [x0,fval0,exitflag] = linprog(f,A,B,Aeq,Beq,lb,ub,options); %决策向量,最优解,是否有解
  35. if exitflag < 0
  36. disp('没有合适整数解');
  37. x = x0;
  38. fval = fval0;
  39. status = exitflag;
  40. return;
  41. else
  42. %采用分支定界法求解
  43. bound = inf;
  44. [x,fval,status] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e);
  45. end

2. 再创建branchbound.m文件

  1. function [newx,newfval,status,newbound] = branchbound(f,A,B,I,x,fval,bound,Aeq,Beq,lb,ub,e)
  2. % 分支定界法求解整数规划
  3. % f,A,B,Aeq,Beq,lb,ub与线性规划相同
  4. % I为整数限制变量的向量
  5. % x为初始解,fval为初始值
  6. options = optimset('display','off');
  7. [x0,fval0,status0]=linprog(f,A,B,Aeq,Beq,lb,ub,options);
  8. %递归中的最终退出条件
  9. %无解或者解比现有上界大则返回原解
  10. if status0 <= 0 || fval0 >= bound
  11. newx = x;
  12. newfval = fval;
  13. newbound = bound;
  14. status = status0;
  15. return;
  16. end
  17. %是否为整数解,如果是整数解则返回
  18. intindex = find(abs(x0(I) - round(x0(I))) > e);
  19. if isempty(intindex) %判断是否为空值
  20. newx(I) = round(x0(I));
  21. newfval = fval0;
  22. newbound = fval0;
  23. status = 1;
  24. return;
  25. end
  26. %当有非整可行解时,则进行分支求解
  27. %此时必定会有整数解或空解
  28. %找到第一个不满足整数要求的变量
  29. n = I(intindex(1));
  30. addA = zeros(1,length(f));
  31. addA(n) = 1;
  32. %构造第一个分支 x<=floor(x(n))
  33. A = [A;addA];
  34. B = [B,floor(x(n))];%向下取整
  35. [x1,fval1,status1,bound1] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e);
  36. A(end,:) = [];
  37. B(:,end) = [];
  38. %解得第一个分支,若为更优解则替换,若不是则保持原状
  39. status = status1;
  40. if status1 > 0 && bound1 < bound
  41. newx = x1;
  42. newfval = fval1;
  43. bound = fval1;
  44. newbound = bound1;
  45. else
  46. newx = x0;
  47. newfval = fval0;
  48. newbound = bound;
  49. end
  50. %构造第二分支
  51. A = [A;-addA];
  52. B = [B,-ceil(x(n))];%向上取整
  53. [x2,fval2,status2,bound2] = branchbound(f,A,B,I,x0,fval0,bound,Aeq,Beq,lb,ub,e);
  54. A(end,:) = [];
  55. B(:,end) = [];
  56. %解得第二分支,并与第一分支做比较,如果更优则替换
  57. if status2 > 0 && bound2 < bound
  58. status = status2;
  59. newx = x2;
  60. newfval = fval2;
  61. newbound = bound2;
  62. end

3. 测试

  1. function[x. fval.stetus] = intprog(f,A,B,I,Aeq,Beq,lb,ub,e)
  2. f = [-20, -10]
  3. A = [5,4;2,5]
  4. B = [24,13]
  5. lb = [0,0]
  6. [x, fval, status] = intprog(f, A, B, [1,2],[],[],lb)

2.2 割平面法

2.2.1 割平面法的基本思想

  • 1. 如果松弛问题(P0)无解,则(P)无解;
  • 2. 如果(P0)的最优解为整数向量,则也是(P)的最优解;
  • 3. 如果(P0)的解含有非整数分量,则对(P0)增加割平面条件:即对(P0)增加一个线性约束,将(P0)的可行区域割掉一块,使得非整数解恰好在割掉的一块中,但又没有割掉原问题(P)的可行解,得到问题(P1),重复上述的过程。

2.2.2 割平面法的基本步骤

注:这里的第二、三步是推理过程,简略来看,只需要看第一步、第二步中1和第四步即可。 

第一步:求解整数规划对应松弛问题是否有整数最优解。若有整数最优解,则它也是整数规划的最优解,否则,转到第二步。

第二步:1. 引入松弛变量转化为等式约束

其中,xi为决策变量,xk为松弛变量,aik为松弛变量的系数,bi与原约束条件一致。

2. 然后,将松弛变量的系数分别划分为整数部分小数部分,如下:

其中,[aik]表示向下取整,Laik也表示aik向下取整,fik表示小数部分(aik减去它整数部分得到的小数,小于0)。

同样,将求和结果划分为整数部分小数部分,如下:

其中,[bi]表示向下取整,Lbi也表示aik向下取整,fi表示小数部分(同上,小于0)。

第三步:将划分后aikbi代入所构建的方程中,可得:

我们将所有的整数部分放入公式左侧,所有的小数部分放入公式右侧:

因为fik小于0,所以0,则可推出:

                                                                xi[bi][aik]

这样就对决策变量进行了一次割平面(增加约束条件)。

第四步:将约束条件 xi[bi][aik] 添加到原数学模型中,重复第一步。

2.2.3 案例和代码实现

已知AM工厂是一个拥有四个车间的玩具生产厂商,该厂商今年新设计出A、B、C、D、E、F六种玩具模型,根据以前的生产情况及市场调查预测,得知生产每单位产品所需的工时、每个车间在一季度的工时上限以及产品的预测价格,如下表所示。问:每种设计产品在这个季度各应生产多少,才能使AM工厂这个季度的生产总值达到最大?

1. 建立模型

 其中,x1,x2,x3,x4,x5,x6是A、B、C、D、E、F六种玩具模型的生产数量。注意,是车间之间是合作生产,而不是独立生产。

2. 引入松弛变量转化为等式约束

3. 代码实现

DividePlane.m

  1. function [intx,intf] = DividePlane(A,c,b,baseVector)
  2. %功能:用割平面法求解整数规划
  3. %调用格式:[intx,intf]=DividePlane(A,c,b,baseVector)
  4. %其中, A:约束矩阵;
  5. % c:目标函数系数向量;
  6. % b:约束右端向量;
  7. % baseVector:初始基向量;
  8. % intx:目标函数取最值时的自变量值;
  9. % intf:目标函数的最值;
  10. sz = size(A);
  11. nVia = sz(2);%获取有多少决策变量
  12. n = sz(1);%获取有多少约束条件
  13. xx = 1:nVia;
  14. if length(baseVector) ~= n
  15. disp('基变量的个数要与约束矩阵的行数相等!');
  16. mx = NaN;
  17. mf = NaN;
  18. return;
  19. end
  20. M = 0;
  21. sigma = -[transpose(c) zeros(1,(nVia-length(c)))];
  22. xb = b;
  23. %首先用单纯形法求出最优解
  24. while 1
  25. [maxs,ind] = max(sigma);
  26. %--------------------用单纯形法求最优解--------------------------------------
  27. if maxs <= 0 %当检验数均小于0时,求得最优解。
  28. vr = find(c~=0 ,1,'last');
  29. for l=1:vr
  30. ele = find(baseVector == l,1);
  31. if(isempty(ele))
  32. mx(l) = 0;
  33. else
  34. mx(l)=xb(ele);
  35. end
  36. end
  37. if max(abs(round(mx) - mx))<1.0e-7 %判断最优解是否为整数解,如果是整数解。
  38. intx = mx;
  39. intf = mx*c;
  40. return;
  41. else %如果最优解不是整数解时,构建切割方程
  42. sz = size(A);
  43. sr = sz(1);
  44. sc = sz(2);
  45. [max_x, index_x] = max(abs(round(mx) - mx));
  46. [isB, num] = find(index_x == baseVector);
  47. fi = xb(num) - floor(xb(num));
  48. for i=1:(index_x-1)
  49. Atmp(1,i) = A(num,i) - floor(A(num,i));
  50. end
  51. for i=(index_x+1):sc
  52. Atmp(1,i) = A(num,i) - floor(A(num,i));
  53. end
  54. Atmp(1,index_x) = 0; %构建对偶单纯形法的初始表格
  55. A = [A zeros(sr,1);-Atmp(1,:) 1];
  56. xb = [xb;-fi];
  57. baseVector = [baseVector sc+1];
  58. sigma = [sigma 0];
  59. %-------------------对偶单纯形法的迭代过程----------------------
  60. while 1
  61. %----------------------------------------------------------
  62. if xb >= 0 %判断如果右端向量均大于0,求得最优解
  63. if max(abs(round(xb) - xb))<1.0e-7 %如果用对偶单纯形法求得了整数解,则返回最优整数解
  64. vr = find(c~=0 ,1,'last');
  65. for l=1:vr
  66. ele = find(baseVector == l,1);
  67. if(isempty(ele))
  68. mx_1(l) = 0;
  69. else
  70. mx_1(l)=xb(ele);
  71. end
  72. end
  73. intx = mx_1;
  74. intf = mx_1*c;
  75. return;
  76. else %如果对偶单纯形法求得的最优解不是整数解,继续添加切割方程
  77. sz = size(A);
  78. sr = sz(1);
  79. sc = sz(2);
  80. [max_x, index_x] = max(abs(round(mx_1) - mx_1));
  81. [isB, num] = find(index_x == baseVector);
  82. fi = xb(num) - floor(xb(num));
  83. for i=1:(index_x-1)
  84. Atmp(1,i) = A(num,i) - floor(A(num,i));
  85. end
  86. for i=(index_x+1):sc
  87. Atmp(1,i) = A(num,i) - floor(A(num,i));
  88. end
  89. Atmp(1,index_x) = 0; %下一次对偶单纯形迭代的初始表格
  90. A = [A zeros(sr,1);-Atmp(1,:) 1];
  91. xb = [xb;-fi];
  92. baseVector = [baseVector sc+1];
  93. sigma = [sigma 0];
  94. continue;
  95. end
  96. else %如果右端向量不全大于0,则进行对偶单纯形法的换基变量过程
  97. minb_1 = inf;
  98. chagB_1 = inf;
  99. sA = size(A);
  100. [br,idb] = min(xb);
  101. for j=1:sA(2)
  102. if A(idb,j)<0
  103. bm = sigma(j)/A(idb,j);
  104. if bm<minb_1
  105. minb_1 = bm;
  106. chagB_1 = j;
  107. end
  108. end
  109. end
  110. sigma = sigma -A(idb,:)*minb_1;
  111. xb(idb) = xb(idb)/A(idb,chagB_1);
  112. A(idb,:) = A(idb,:)/A(idb,chagB_1);
  113. for i =1:sA(1)
  114. if i ~= idb
  115. xb(i) = xb(i)-A(i,chagB_1)*xb(idb);
  116. A(i,:) = A(i,:) - A(i,chagB_1)*A(idb,:);
  117. end
  118. end
  119. baseVector(idb) = chagB_1;
  120. end
  121. %------------------------------------------------------------
  122. end
  123. %--------------------对偶单纯形法的迭代过程---------------------
  124. end
  125. else %如果检验数有不小于0的,则进行单纯形算法的迭代过程
  126. minb = inf;
  127. chagB = inf;
  128. for j=1:n
  129. if A(j,ind)>0
  130. bz = xb(j)/A(j,ind);
  131. if bz<minb
  132. minb = bz;
  133. chagB = j;
  134. end
  135. end
  136. end
  137. sigma = sigma -A(chagB,:)*maxs/A(chagB,ind);
  138. xb(chagB) = xb(chagB)/A(chagB,ind);
  139. A(chagB,:) = A(chagB,:)/A(chagB,ind);
  140. for i =1:n
  141. if i ~= chagB
  142. xb(i) = xb(i)-A(i,ind)*xb(chagB);
  143. A(i,:) = A(i,:) - A(i,ind)*A(chagB,:);
  144. end
  145. end
  146. baseVector(chagB) = ind;
  147. end
  148. M = M + 1;
  149. if (M == 1000000)
  150. disp('找不到最优解!');
  151. mx = NaN;
  152. minf = NaN;
  153. return;
  154. end
  155. end

test.m

  1. c = [-20 ; -14 ; -16 ; -36 ; -32 ; -30]; % 目标函数系数向量
  2. A = [0.01 0.01 0.01 0.03 0.03 0.03 1 0 0 0;
  3. 0.02 0 0 0.05 0 0 0 1 0 0;
  4. 0 0.02 0 0 0.05 0 0 0 1 0;
  5. 0 0 0.03 0 0 0.08 0 0 0 1]; % 加上松弛变量后约束条件的系数矩阵
  6. b = [850; 700; 100; 900;]; % 约束右端向量
  7. [intx , intf] = DividePlane(A,c,b,[7 8 9 10]); % 初始基向量的下标 7 8 9 10
  8. intx
  9. intf = -intf % 取反求最大

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/435325
推荐阅读
相关标签
  

闽ICP备14008679号