从零开始的数模(二)整数规划

目录

一、概念

1.3例题

二、分枝定界法

python代码失败

三、割平面法

四、0-1整数规划

4.1匈牙利算法

 4.2过滤隐枚举法

4.3蒙特卡洛随机取样法求解


一、概念

松弛变量  剩余变量
1.1整数规划的定义:
数学规划中的变量(部分或者全部)限制为整数的时候,称为整数规划。
整数规划的分类:
如果不加特殊说明,指的就是整数线性规划(在线性规划的模型中变量限制为整数)。分为两类:
1:变量全部限制为整数,称纯整数规划
2:变量部分限制为整数,称混合整数规划。
整数规划的特点:
1:原线性规划的最优解全是整数,则自变量限制为整数之后,最优解不变。
2:整数规划没有可行解。
0-1型整数规划
顾名思义,在该模型下,变量xi的值只能取到0或者1,称xi为0-1变量或者二进制变量。可由约束条件 0 <= xi <= 1而且xi为整数所代替。
在一些互相排斥的约束问题:比如两种方式可供选择,但是只能选择一种的情形。
在一些指派问题的数学模型中:比如:n个人分配去做n项工作,每个人都做且都只能做一项工作。

1.2关系

又不理解了吧,没关系上题

1.3例题

应用于运输问题、指派问题

1.4方法

i)分枝定界法—可求纯或混合整数线性规划。

(ii)割平面法—可求纯或混合整数线性规划。

(iii)隐枚举法—求解“0-1”整数规划:    

①过滤隐枚举法;    
②分枝隐枚举法。
(iv)匈牙利法—解决指派问题(“0-1”规划特殊情形)。

(v)蒙特卡洛法—求解各种类型规划。

二、分枝定界法

  • 分枝定界法适用于求解完全整数规划混合整数规划,混合整数规划相比较而言更加简单,只需要针对非限定为整数的变量不分枝即可。
  • 我们首先来了解一下分枝定界法中三个基本操作的含义。分枝:将全部可行解空间分割为越来越小的子集;定界:对于分枝后的每一个子集计算目标函数值得上界与下界;剪枝:根据上下界忽略掉超出界限得部分可行解。下面我们首先通过一个例题,以手写算法得方式来感受一下算法过程。

上题

在这里插入图片描述

 总结来说,分枝定界法多次计算线性规划,缩小搜索范围,逼近整数规划的最优解。针对线性规划问题我们已经有了高效便捷的算法,因此多次计算线性规划问题解决整数规划问题同样具有效率

python代码失败

import math
from scipy.optimize import linprog
import sys

def integerPro(c, A, b, Aeq, beq,t=1.0E-12):
    # 求解松弛问题
    res = linprog(c, A_ub=A, b_ub=b, A_eq=Aeq, b_eq=beq)
    bestVal = sys.maxsize
    bestX = res.x
    if not(type(res.x) is float or res.status != 0): 
        bestVal = sum([x*y for x,y in zip(c, bestX)])
    # 停止条件 & bound
    if all((int((x-math.floor(x)))<t or int((math.ceil(x)-x)<t)) for x in bestX):
        return (bestVal,bestX)
    else:
        # 进行branch,这里简单选择第一个非整数变量
        ind = [i for i, x in enumerate(bestX) if (x-math.floor(x))>t and (math.ceil(x)-x)>t][0]
        # branch出两个子问题
        newCon1 = [0]*len(A[0])
        newCon2 = [0]*len(A[0])
        newCon1[ind] = -1
        newCon2[ind] = 1
        newA1 = A.copy()
        newA2 = A.copy()
        newA1.append(newCon1)
        newA2.append(newCon2)
        newB1 = b.copy()
        newB2 = b.copy()
        newB1.append(-math.ceil(bestX[ind]))
        newB2.append(math.floor(bestX[ind]))
        r1 = integerPro(c, newA1, newB1, Aeq, beq)
        r2 = integerPro(c, newA2, newB2, Aeq, beq)
        # tree search,这里使用width first
        if r1[0] < r2[0]:
            return r1
        else:
            return r2
c = [-5,-8]
A = [[1,1],[5,9]]
b = [6,45]
Aeq = [[0,0]]
beq = [0]
print(integerPro(c, A, b, Aeq, beq))

  • Lingo代码如下:
  • model:
    max=5*x1+8*x2;
    x1+x2<6;
    5*x1+9*x2<45;
    @gin(x1);
    @gin(x2);
    end
    

三、割平面法

基本思想:

1.如果松弛问题(P0)无解,则(P)无解;

2.如果(P0)的最优解为整数向量,则也是(P)的最优解;

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

上例题

基于cvxpy下的线性规划

import cvxpy as cp
import numpy as np

# 不懂见数学原型中的定义, 什么价值向量资源向量什么的
c = np.array([3,1,3])
a = np.array([[-1,2,1],[0,4,-3],[1,-3,2]])

b = np.array([4,2,3])

######
x = cp.Variable(3)	# 用cvxpy来定义两个整数决策变量, 也就是约束x为整数

obj = cp.Maximize(c*x) 	# 目标函数

cons = [a * x <= b, x >= 0]		# 约束条件
prob = cp.Problem(obj, cons)	# 构建问题模型


prob.solve(solver='GLPK_MI', verbose=True) # 求解
print("最优值", prob.value)
print("最优解", x.value)

基于cvxpy下的整数规划

#导入numpy
import numpy as np
#导入numpy
import cvxpy as cp

#设置目标函数中变量个数
n=3

#输入目标函数的系数
c=np.array([3,1,3])

#输入约束条件的系数矩阵(3×3)
a=np.array([[-1,2,1],[0,4,-3],[1,-3,2]])

#输入b值(3×1)
b=np.array([4,2,3])

#创建x,个数是3
x=cp.Variable(n,integer=True)

#明确目标函数(此时c是3×1,x是3×1,但python里面可以相乘)
objective=cp.Maximize(cp.sum(c*x))

#明确约束条件,其中a是3×3,x是3×1,a*x=b(b为3×1的矩阵)
constriants=[0<=x,a*x<=b]
#求解问题
prob=cp.Problem(objective,constriants)
#这里solver必须使用cp.CPLEX,否则计算不出来,而CPLEX需要pip intall CPLEX(建议使用清华镜像)
resluts=prob.solve(solver=cp.CPLEX)

#输入结果
print(prob.value)#目标函数的值
print(x.value)#各x的值

基于Matlab的实现

函数原型

[x, fval] = intlinprog(c, intcon, A, b, Aeq, beq, lb, ub)

基本上和 linprog() 一样, intcon参数就是指定哪些变量有整数约束

例题 

 

c = [-5; -8];		
% 无论线性规划还是整数规划, 在matlab中默认都是求最小值,
% 题目要求最大值, 所以加个负号

A = [1, 1;
     5, 9];
 
b = [6; 45];

lb = zeros(2, 1);

intcon = [1, 2];	
% 着重看上面这个, 这里指定了x1, x2为整数
% 所以根据4.1.2数学原型中写到的intcon的意义, intcon = [1, 2]

[x, fval] = intlinprog(c, intcon, A, b, [], [], lb, []);

x
-fval 	% 因为之前为了求最大值加了负号, 所以这里再把答案负回来

四、0-1整数规划

指派问题

4.1匈牙利算法

 

 

 

 

 Matlab解法

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(:); %把矩阵c转换成向量
a=zeros(10,25); %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);
[x,y]=linprog(c,[],[],a,b,zeros(25,1),ones(25,1));
X=reshape(x,5,5) %重构成矩阵
opt=y

 python解法

from scipy.optimize import linear_sum_assignment
 
cost =np.array([[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]])
row_ind,col_ind=linear_sum_assignment(cost)
print(row_ind)#开销矩阵对应的行索引
print(col_ind)#对应行索引的最优指派的列索引
print(cost[row_ind,col_ind])#提取每个行索引的最优指派列索引所在的元素,形成数组
print(cost[row_ind,col_ind].sum())#数组求和

 4.2过滤隐枚举法

4.3蒙特卡洛随机取样法求解

先给出一个例子:
y = x^2, y = 12 - x与x轴在第一象限围成一个曲边三角形,设计一个随机试验求该图形的面积。

分析:可以在一个已知矩形面积(包含所求的曲边三角形)的矩形中生成n个随机数之后统计落在去边三角形中的随机数的个数,之后计算比值,从而得出面积。

clc
clear
x = unifrnd(0, 12, [1, 100000]);
y = unifrnd(0, 9, [1, 100000]);
ps = sum(y < x .^ 2 & x <= 3) + sum(y < 12 - x & x >= 3)
area = ps/100000 * 9 * 12

整数线性规划的计算机求解

在这里插入图片描述

在Matlab中求解混合整数线性规划的命令为

[x, fval] = intlinprog(f, intcon, a, b, aeq, beq, lb, ub)
% f, x, intcon, beq, lb, ub为列向量;a, aeq为矩阵。

 例题在这里插入图片描述

 Matlab解法

clc
clear
f = [-3;-2;-1]
intcon = 3
a = ones(1,3)
b = 7
aeq = [4 2 1]
beq = 12
lb = zeros(3,1)
ub = [inf;inf;1]
x = intlinprog(f, intcon, a, b, aeq, beq, lb, ub)
% 求得最优解为x1 = 0, x2 = 5.5, x3 = 1; 目标函数的最优值为 z = -12。

例:

对于非线性整数规划,可使用蒙特卡洛法进行估算:

python解法:速度超级慢

import numpy as np


def check(x):
    if x.sum() > 400:
        return False
    if x[0]+2*x[1]+2*x[2]+x[3]+6*x[4] > 800:
        return False
    if 2*x[0]+x[1]+6*x[2]>200:
        return False
    if x[2]+x[3]+5*x[3]>200:
        return False

    return True


def get_radom():
    x = np.random.randint(100, size=5)
    while not check(x):
        x = get_radom()
    return x


lim = 10**6
ans = -1

for i in range(lim):
    num = get_radom()
    ans = max(ans, num.all())
    if i % 10000 == 0:
        print(i)

print('ans=' + ans)

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟雨平生9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值