建模算法(二)——整數規划


一、概述

1、定義:規划中變量部分或全部定義成整數是,稱為整數規划。

2、分類:純整數規划和混合整數規划。

3、特點:

(1)原線性規划有最優解,當自變量限制為整數后:

       a、原最優解全是整數,那最優解仍成立

       b、整數規划沒有可行解

       c、有可行解,但是不是原最優解

4、求解方法分類

(1)分支定界法

(2)割平面法

(3)隱枚舉法

(4)匈牙利法

(5)蒙特卡洛法

 

二、分支定界法

1、算法如下(求解整數規划最大化問題)

image

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、實際問題:

image

       這里我們就可以直接列出一個是0-1規划的方程,設的變量xi,“1”表示被選中,“0”表示沒被選中

3、相互排斥的約束條件可以轉化成同類型的。

image

image

四、求解整數規划的3種方法

(1)窮舉法,這種比較土= =,但是最有效,而且某些情況只能窮舉。

(2)過渡隱枚舉法

a、先試探性求一個可行解X(隨便帶入求值)

b、然后根據是求極大值還是極小值,如果是求極大值,那么凡是目標值<X的解不必檢驗是否滿足約束條件即可刪除,如果是求極小值,那么凡是目標值>X不必檢驗是否滿足約束條件就可滿足。

c、改進新的過濾條件

d、然后驗證目標值,最終求得。

PS:怎么說呢,這個方法就是一種變相的窮舉,如果運氣不好,就會變成全部都窮舉,但是因為是先比較目標值,所以可以減少計算量,因而還是有效的(但是要注意不要犯反復測驗的錯誤)、

(3)蒙特卡洛法(隨機抽樣法)

就是選擇不窮舉全部點,而是采用隨機的方式來抽取樣本估計整體,如果樣本足夠大,可信度是很大的。

例如求解此題:

image

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整數規划的求解

例如求解這個指派問題。

image

由於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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM