一、概述
1、定義:規划中變量部分或全部定義成整數是,稱為整數規划。
2、分類:純整數規划和混合整數規划。
3、特點:
(1)原線性規划有最優解,當自變量限制為整數后:
a、原最優解全是整數,那最優解仍成立
b、整數規划沒有可行解
c、有可行解,但是不是原最優解
4、求解方法分類
(1)分支定界法
(2)割平面法
(3)隱枚舉法
(4)匈牙利法
(5)蒙特卡洛法
二、分支定界法
1、算法如下(求解整數規划最大化問題)
MATLAB實現
function r=checkint(x) %判斷x(i)是不是整數了。是的話r(i)返回1,不是的話,返回0 %輸入參數:x X向量 %輸出參數:r R向量 for i=1:length(x) if(min(abs(x(i)-floor(x(i))),abs(x(i)-ceil(x(i))))<1e-3) r(i)=1; else r(i)=0; end end
function val=isrowinmat(arow,mat) %用來判斷mat中是否包含與arow一樣的向量 %輸入變量:arow 向量 % mat 矩陣 %輸出變量:val 1表示有,0表示沒有 val=0; rows=size(mat,1); for i=1:rows temp=(mat(i,:)==arow); if length(find(temp==0))==0 val=1; return; else val=0; end; end
function [x,fval,exitflag,output,lambda]=linprogdis(ifint,f,A,b,Aeq,beq,lb,ub,x0,options) % 用法 % [x,fval,exitflag,output,lambda]=lpint(ifint.f,A,b,Aeq,beq) % [x,fval,exitflag,output,lambda]=lpint(ifint,f,A,b,Aeq,beq,lb) % [x,fval,exitflag,output,lambda]=lpint(ifint,f,A,b,Aeq,beq,lb,ub) % [x,fval,exitflag,output,lambda]=lpint(ifint,f,A,b,Aeq,beq,lb,ub,x0) % [x,fval,exitflag,output,lambda]=lpint(ifint,f,A,b,Aeq,beq,lb,ub,x0,options) if nargin<10, options=[]; end if nargin<9, x0=[]; end if nargin<8, ub=inf*ones(size(f)); end if nargin<7, lb=zeros(size(f)); end [x,fval,exitflag,output,lambda]=linprog(f,A,b,Aeq,beq,lb,ub,x0,options); if exitflag<=0 %表示線性規划沒有最優解 return end v1=find(ifint==1); %找到需要整數規划的變量的下標 temp=x(v1);%如果不是要求整數規划的就可以返回了。 if isempty(temp) return end v2=find(checkint(temp)==0); if isempty(v2) %都是整數,得到最眾解 return end k=v1(v2(1)); temp1=zeros(1,length(f)); temp1(k)=1; low=floor(x(k)); if isrowinmat([temp1,low],[A,b])==1 thisA=A; thisb=b; else thisA=[A;temp1]; thisb=b; thisb(end+1)=low; end [x1,fval1,exitflag1,output1,lambda1]=linprogdis(ifint,f,thisA,thisb,Aeq,beq,lb,ub,x0,options); temp2=zeros(1,length(f)); temp2(k)=-1; high=-ceil(x(k)); if isrowinmat([temp2,high],[A,b])==1 thisA=A; thisb=b; else thisA=[A;temp2]; thisb=b; thisb(end+1)=high; end [x2,fval2,exitflag2,output2,lambda2]=linprogdis(ifint,f,thisA,thisb,Aeq,beq,lb,ub,x0,options); if (isempty(v2) && ((exitflag1>0 && exitflag2<=0 && fval<=fval)||(exitflag2>0 && exitflag1<=0 && fval<=fval2)||(exitflag1>0 && exitflag2>0 && fval<=fval1 && fval<=fval2))) disp('error call'); return ; %表示都是整數 end if exitflag1>0&&exitflag2<=0 x=x1; fval=fval1; exitflag=exitflag1; output=output1; lambda=lambda1; elseif exitflag1<=0&&exitflag2>0 x=x2; fval=fval2; exitflag=exitflag2; output=output2; lambda=lambda2; elseif exitflag1>0 && exitflag2>0 if fval1<fval2 x=x1; fval=fval1; exitflag=exitflag1; output=output1; lambda=lambda1; else x=x2; fval=fval2; exitflag=exitflag2; output=output2; lambda=lambda2; end end
三、0-1型整數規划
1、定義:就是變量的取值只能是0-1,這樣的話,其實我們可以將不同的整數規划轉化成0-1規划。
2、實際問題:
這里我們就可以直接列出一個是0-1規划的方程,設的變量xi,“1”表示被選中,“0”表示沒被選中
3、相互排斥的約束條件可以轉化成同類型的。
四、求解整數規划的3種方法
(1)窮舉法,這種比較土= =,但是最有效,而且某些情況只能窮舉。
(2)過渡隱枚舉法
a、先試探性求一個可行解X(隨便帶入求值)
b、然后根據是求極大值還是極小值,如果是求極大值,那么凡是目標值<X的解不必檢驗是否滿足約束條件即可刪除,如果是求極小值,那么凡是目標值>X不必檢驗是否滿足約束條件就可滿足。
c、改進新的過濾條件
d、然后驗證目標值,最終求得。
PS:怎么說呢,這個方法就是一種變相的窮舉,如果運氣不好,就會變成全部都窮舉,但是因為是先比較目標值,所以可以減少計算量,因而還是有效的(但是要注意不要犯反復測驗的錯誤)、
(3)蒙特卡洛法(隨機抽樣法)
就是選擇不窮舉全部點,而是采用隨機的方式來抽取樣本估計整體,如果樣本足夠大,可信度是很大的。
例如求解此題:
MATLAB編程求解:
function [ f,g ] = mengte( x ) %MENGTE 鍵入整數線性規划的目標函數和約束條件 % f:指的是目標函數 向量 % g:指的是約束條件 向量 f=x(1)^2+x(2)^2+3*x(3)^2+4*x(4)^2+2*x(5)^2-8*x(1)-2*x(2)-3*x(3)-x(4)-2*x(5); g=[sum(x)-400 x(1)+2*x(2)+2*x(3)+x(4)+6*x(5)-800 2*x(1)+x(2)+6*x(3)-200 x(3)+x(4)+5*x(5)-200]; end
rand('state',sum(clock)); p0=0; tic for i=1:10^6 x=99*rand(5,1); x1=floor(x);x2=ceil(x); [f,g]=mengte(x1); if sum(g<=0)==4 if p0<=f x0=x1;p0=f; end end [f,g]=mengte(x2); if sum(g<=0)==4 if p0<=f x0=x2;p0=f; end end end x0,p0
五、0-1整數規划的求解
例如求解這個指派問題。
由於MATLAB里面有封裝好的函數- -,我就不用C++再寫了。。不過這個問題還是很容易寫出來的,一些比賽題目也會出現的。
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:1:5*i)=1; a(5+i,i:5:25)=1; end b=ones(10,1); [x,y]=bintprog(c,[],[],a,b); x=reshape(x,[5,5]),y