问题描述:
某公司用两种原油(
A
和
B
)混合加工成两种汽油(甲和乙)。甲、乙两种
汽油含原油A的最低比例分别为
50
%和
60
%,每吨售价分别为
4800
元和
5600
元。该公
司现有原油
A
和
B
的库存量分别为
500
吨和
1000
吨,还可以从市场上买到不超过
1500
吨的原油
A
。原油
A
的市场价为:购买量不超过
500
吨时的单价为
10000
元
/
吨;购买
量超过
500
吨单不超过
1000
吨时,超过
500
吨的部分
8000
元
/
吨;购买量超过
1000
吨
时,超过
1000
吨的部分
6000
元
/
吨。该公司应如何安排原油的采购和加工。
数学建模:
判定此问题为一个线性规划问题,因为线性规划问题具有以下几个特征:
1、线性目标函数:
很显然,这个问题的目标函数为成本减去利益,并且变量*价格遵循这样简单的乘法关系,因此可以看作是一个线性的目标函数
2、线性约束条件:
- 原油 A 和 B 的库存和购买量限制。
- 汽油甲和乙生产中原油 A 和 B 的比例要求。
- 购买原油 A 的数量限制。
- 非负约束,确保所有生产量和购买量都不会是负数。
- 所有这些约束都可以用线性表达式来表达,满足线性规划的条件
3、变量的连续性:
在标准的线性规划模型中,决策变量可以取连续值。虽然在实际应用中,如原油购买量通常为整数(即吨),但在模型计算中可以假设这些变量是连续的,从而允许使用线性规划技术找到最优解。如果需要,可以对结果进行四舍五入处理以满足实际应用的要求。
问题分析:
这个问题可以被看成是一个线性规划模型,因为他原题中给出了A和B的采购价格,为收入;题目中给出了A的市场价格,是额外购买A所需要的成本,为支出,那么目标函数就显而易见。约束条件主要体现在题目当中“不超过”等字眼当中,还有原油A的占比问题,以及相应的一些关于生活中实际情况的描述。
变量设置:
设原油
A
用于生产甲、乙两种汽油的数量分别为
x
11
和
x
12
,原油
B
用于生产甲、
乙两种汽油的数量分别为
x
21
和
x
22
,则总的收入为
4.8(
x
11
+
x
21
)
+
5.6(
x
12
+
x
22
)
(千
元)。于是本例的目标函数(利润)为
max
z
=
4.8(
x
11
+
x
21
)
+
5.6(
x
12
+
x
22
)
−
c
(
x
)
问题的数学表述:
问题求解:
解法一: 把cx分段函数的x换成三个变量 x1 x2 x3,然后对其进行相关的列些,避免因为分段函数产生的相关麻烦。因此,c(x)可以改写为 10x1+8x2+6x3,
这时目标函数
变为线性函数:
max
z
=
4.8(
x
11
+
x
21
)
+
5.6(
x
12
+
x
22
)
−
(10
x
1
+
8
x
2
+
6
x
3
)
应该注意到,只有当以
10
千元
/
吨的价格购买
x
1
=
500
(吨)时,才能以
8
千元
/
吨的价格购买
x
2
(
>
0)
,这个条件可以表示为
(
x
1
−
500)
x
2
=
0
同理,只有当以
8
千元
/
吨的价格购买
x
2
=
500
(吨)时,才能以
6
千元
/
吨的价格购买
x
3
(
>
0)
,于是
(
x
2
−
500)
x
3
=
0
此外,
x
1
,
x
2
,
x
3
的取值范围是
0
≤
x
1
,
x
2
,
x
3
≤
500
线性规划代码使用LINGO软件比较方便,
model:
sets:
var1/1..4/:y;
var2/1..3/:x,c;
endsets
max=4.8*(y(1)+y(2))+5.6*(y(3)+y(4))-@sum(var2:c*x);
y(1)+y(3)<@sum(var2:x)+500;
y(2)+y(4)<1000;
0.5*(y(1)-y(2))>0;
0.4*y(3)-0.6*y(4)>0;
(x(1)-500)*x(2)=0;
(x(2)-500)*x(3)=0;
@for(var2:@bnd(0,x,500));
data:
c=10 8 6;
enddata
end
sets:
var1/1..4/:y;
var2/1..3/:x,c;
endsets
max=4.8*(y(1)+y(2))+5.6*(y(3)+y(4))-@sum(var2:c*x);
y(1)+y(3)<@sum(var2:x)+500;
y(2)+y(4)<1000;
0.5*(y(1)-y(2))>0;
0.4*y(3)-0.6*y(4)>0;
(x(1)-500)*x(2)=0;
(x(2)-500)*x(3)=0;
@for(var2:@bnd(0,x,500));
data:
c=10 8 6;
enddata
end
非线性规划使用LINGO求解更方便:
LINGO运行截图
如图所示,可知,5000,为最值,并且,此时x12值为1500 x22值为1000,所以购买
购买
1000
吨原油
A
,与库存的
500
吨原油
A
和
1000
吨原油
B
一起,共生产
2500
吨汽油乙,利润为
5000
(千元)。
解法二:
引入
0
-
1
变量将
转化为线性约束。
令
z
1
=
1
,
z
2
=
1
,
z
3
=
1
分别表示以
10
千元
/
吨、
8
千元
/
吨、
6
千元
/
吨的价格采
购原油
A ,
500
z
2
≤
x
1
≤
500
z
1
,
(
18
)
500
z
3
≤
x
2
≤
500
z
2
,
(
19
)
x
3
≤
500
z
3
,
(
20
)
z
1
,
z
2
,
z
3
=
0
或
1
LINGO代码如下:
model:
sets:
var1/1..4/:y; !
这里
y(1)=x11,y(2)=x21,y(3)=x12,y(4)=x22;
var2/1..3/:x,z,c;
endsets
max=4.8*(y(1)+y(2))+5.6*(y(3)+y(4))-@sum(var2:c*x);
y(1)+y(3)<@sum(var2:x)+500;
y(2)+y(4)<1000;
0.5*(y(1)-y(2))>0;
0.4*y(3)-0.6*y(4)>0;
@for(var1(i)|i #lt# 3:500*z(i+1)<x(i);x(i)<500*z(i));
x(3)<500*z(3);
@for(var2:@bin(z));
@for(var2:@bnd(0,x,500));
data:
c=10 8 6;
enddata
end
解法三:
把cx直接当成分段函数来处理。 此时,根据分段函数定义域的三个分界点为0 500 1000 可以定义出[0,b1] , [b1,b2],[b2,b3]这三个小区间。
x
属于第
1
个小区间
[
b
1
,
b
2
]
时,记
x
=
w
1
b
1
+
w
2
b
2
,
w
1
+
w
2
=
1
,
w
1
,
w
2
≥
0
,因为
c
(
x
)
在
[
b
1
,
b
2
]上是线性的,
所 以
c
(
x
)
=
w
1
c
(
b
1
)
+
w
2
c
(
b
2
)
。同样,当
x
属于第
2
个小区间
[
b
2
,
b
3
]
时 ,
x
=
w
2
b
2
+
w
3
b
3
,
w
2
+
w
3
=
1
,
w
2
,
w
3
≥
0
,
c
(
x
)
=
w
2
c
(
b
2
)
+
w
3
c
(
b
3
)
。当
x
属于第
3
个小区间
[
b
3
,
b
4
]
时 ,
x
=
w
3
b
3
+
w
4
b
4
,
w
3
+
w
4
=
1
,
w
3
,
w
4
≥
0
,
c
(
x
)
=
w
3
c
(
b
3
)
+
w
4
c
(
b
4
)
。为了表示
x
在哪个小区间,引入
0-1
变量
z
k
(
k
=
1,2,3)
,
当
x
在第
k
个小区间时,
z
k
=
1
,否则,
z
k
=
0
。
w
1
≤
z
1
,
w
2
≤
z
1
+
z
2
,
w
3
≤
z
2
+
z
3
,
w
4
≤
z
3
(
22
)
w
1
+
w
2
+
w
3
+
w
4
=
1
,
w
k
≥
0
(
k
=
1,2,3,4
)
(
23
)
z
1
+
z
2
+
z
3
=
1
,
z
1
,
z
2
,
z
3
=
0
或
1
(
24
)
此时
x
和
c
(
x
)
可以统一地表示为
x
=
w
1
b
1
+
w
2
b
2
+
w
3
b
3
+
w
4
b
4
=
500
w
2
+
1000
w
3
+
1500
w
4
(
25
)
c
(
x
)
=
w
1
c
(
b
1
)
+
w
2
c
(
b
2
)
+
w
3
c
(
b
3
)
+
w
4
c
(
b
4
)
=
5000
w
2
+
9000
w
3
+
12000
w
4
LINGO代码
model:
sets:
var/1..4/:b,c,y,z,w;
!
这里
y(1)=x11,y(2)=x21,y(3)=x12,y(4)=x22
端点数为4,即分段数为3;
endsets
data:
b=0,500,1000,1500;
c=0,5000,9000,12000;
z=,,,0; !
增加的虚拟变量z(4)=0;
enddata
max=4.8*(y(1)+y(2))+5.6*(y(3)+y(4))-@sum(var:c*w);
y(1)+y(3)<@sum(var:b*w)+500;
y(2)+y(4)<1000;
0.5*(y(1)-y(2))>0;
0.4*y(3)-0.6*y(4)>0;
w(1)<z(1);
@for(var(i)|i #ne# 1:w(i)<z(i-1)+z(i));
@sum(var:z)=1;
@sum(var:w)=1;
@for(var:@bin(z));
End
运行结果与上面完全相同。