2020年全国大学生数学建模竞赛B题 穿越沙漠
题目是讲玩家在不同地图下穿越沙漠,所获得的资金数要最多(大概是这个意思)。然后通过文章的描述又总结了N个约束条件。整体的思路就是对资金最大化作为目标函数在给定约束,利用具体(已知)条件,进行单目标优化。
总的分三小问:
第一问:玩家在已知每天天气条件下,对地图1和2进行路径规划。
第二问:玩家在未知每天天气条件下,对地图3和4进行路径规划。
第三问:多个玩家游戏,讨论已知天气条件(地图5)和未知天气条件(地图6)的合理决策。
每个地图在Result.xls附录中给出了具体的信息,其中包括:
地图拓扑结构,初始购买金额限值,负重限制,日期限值,不同天气对当日物资消耗的影响。
玩家总的思路就是从起点去往终点,在路途中确定当天合适的决策(移动/停留),物资不能消耗殆尽(不能饿死也不能渴死)。如果选择在矿山停留可以选择挖矿,经过村落可以通过资金进行补给,最后到达终点时使剩余资金最大化。
确定好思路后,就可以开始建模了。
主要考虑四大部分:
已知条件、决策变量、约束条件、目标函数
1.已知条件:
前两问给出了已知的天气情况,这里用
w
i
w_i
wi表示第
i
i
i天的天气:
w
i
=
{
1
2
3
晴朗
高温
沙暴
w_i=\left\{ \begin{array}{c} 1\\ 2\\ 3\\ \end{array} \right. \begin{array}{c} \text{晴朗}\\ \text{高温}\\ \text{沙暴}\\ \end{array}
wi=⎩⎨⎧123晴朗高温沙暴
根据题目给出的已知信息,可以知道对应基础水和食物的消耗量分别为:
p
i
=
{
5
8
10
w
i
=
1
w
i
=
2
w
i
=
3
q
i
=
{
7
6
10
w
i
=
1
w
i
=
2
w
i
=
3
p_i=\left\{ \begin{array}{c} 5\\ 8\\ 10\\ \end{array} \right. \begin{array}{c} w_i=1\\ w_i=2\\ w_i=3\\ \end{array}\,\, q_i=\left\{ \begin{array}{c} 7\\ 6\\ 10\\ \end{array} \right. \begin{array}{c} w_i=1\\ w_i=2\\ w_i=3\\ \end{array}
pi=⎩⎨⎧5810wi=1wi=2wi=3qi=⎩⎨⎧7610wi=1wi=2wi=3
2.决策变量:
初始食物和水的购买量:X,Y均为正整数
村落食物和水的补给量:CX,CY均为正整数
当日行动决策变量均为0-1变量:
x
j
k
i
=
{
1
第
i
天从地方
j
走向地方
k
0
其他
z
1
i
=
{
1
停留
0
行走
z
2
i
=
{
1
挖矿
0
不挖矿
z
3
i
=
{
1
购买物资
0
不购买物资
x_{jk}^{i}=\left\{ \begin{array}{c} 1 \text{ 第}i\text{天从地方}j\text{走向地方}k\\ 0 \text{ 其他}\\ \end{array} \right. \\ \,\, \\ \,\,z1_i=\left\{ \begin{array}{c} 1 \text{ 停留}\\ 0 \text{ 行走}\\ \end{array} \right. \,\, \\ \,\, \\ z2_i=\left\{ \begin{array}{c} 1 \text{ 挖矿}\\ 0 \text{ 不挖矿}\\ \end{array} \right. \,\, \\ \,\, \\ z3_i=\left\{ \begin{array}{c} 1 \text{ 购买物资}\\ 0 \text{ 不购买物资}\\ \end{array} \right.
xjki={1 第i天从地方j走向地方k0 其他z1i={1 停留0 行走z2i={1 挖矿0 不挖矿z3i={1 购买物资0 不购买物资
3.约束条件
物资(水和食物)的重量限制和初始资金限制:
{
w
e
i
g
h
t
=
3
X
+
2
Y
⩽
1200
c
o
s
t
=
5
X
+
10
Y
⩽
10000
\left\{ \begin{array}{c} weight=3X+2Y\leqslant 1200\\ cost=5X+10Y\leqslant 10000\\ \end{array} \right.
{weight=3X+2Y⩽1200cost=5X+10Y⩽10000
对于移动我们只能在相邻的区域之间进行移动,因此我们需要通过matlab对图区域之间的接壤情况列出距离矩阵
d
i
j
d_{ij}
dij:
d
i
j
=
{
1
0
区域
i
与区域
j
接壤
不接壤
d_{ij}=\begin{cases} 1\\ 0\\ \end{cases}\begin{array}{c} \text{区域}i\text{与区域}j\text{接壤}\\ \text{不接壤}\\ \end{array}
dij={10区域i与区域j接壤不接壤
列出距离矩阵后,对决策变量进行限制,使玩家只能在相邻区域之间进行移动:
x
j
k
i
⩽
d
j
k
{x_{jk}^{i}}\leqslant d_{jk}
xjki⩽djk
每天的决策只能有一个,要么在某地停留要么移动,因此有约束条件:
∑
j
=
1
N
∑
k
=
1
N
x
j
k
i
=
1
\sum_{j=1}^N{\sum_{k=1}^N{x_{jk}^{i}}}=1
j=1∑Nk=1∑Nxjki=1
首先第1天要从起点1开始出发去往某地k,于是便有:
∑
k
=
1
N
x
1
k
1
=
1
\sum_{k=1}^N{x_{1k}^{1}}=1
k=1∑Nx1k1=1
其次我们需要保证路径是连续的,因此当天的出发地要是前一天的目的地:
∑
j
=
1
N
x
j
k
i
=
∑
j
=
1
N
x
k
j
i
+
1
\sum_{j=1}^N{x_{jk}^{i}}\,\,=\sum_{j=1}^N{x_{kj}^{i+1}}
j=1∑Nxjki=j=1∑Nxkji+1
最后需要某一天抵达终点,因此需要保证:
∑
i
=
1
n
∑
k
=
1
N
−
1
x
k
N
i
=
1
\sum_{i=1}^{n}{\sum_{\begin{array}{c} k=1 \end{array}}^{N-1}{x_{kN}^{i}}}=1
i=1∑nk=1∑N−1xkNi=1
到达终点停止,若到达终点,未满30天,后面的天数则视为在终点处停留,不消耗物资,资金数也不发生变化:
∑
j
=
1
N
x
j
27
i
−
x
2727
i
+
1
=
0
\sum_{j=1}^N{x_{j\,\,27}^{i}-x_{27 27}^{i+1}}=0
j=1∑Nxj27i−x2727i+1=0
如果第
i
i
i天想在某地
j
j
j停留则可以表示为:
x
j
j
i
=
1
x_{jj}^{i}=1
xjji=1,那么表示停留/行走的0-1变量
z
1
i
z1_i
z1i就需要满足表达式:
z
1
i
=
∑
j
=
1
N
x
j
j
i
z1_i=\sum_{j=1}^N{x_{jj}^{i}}
z1i=j=1∑Nxjji
题目给定的额外条件有:
沙暴天气一定得停留:
w
i
−
∑
j
=
1
n
x
j
j
i
⩽
2
w_i-\sum_{j=1}^n{x_{jj}^{i}}\leqslant 2
wi−j=1∑nxjji⩽2
停留矿山可以挖矿,设矿山为
m
m
m则有:
z
2
i
⩽
x
m
m
i
z2_i\leqslant x_{mm}^{i}
z2i⩽xmmi
途径村落可以购买物资,设村庄为
t
t
t则有:
z
3
i
⩽
∑
j
=
1
N
x
t
j
i
+
x
j
t
i
z3_i\leqslant \sum_{j=1}^N{x_{tj}^{i}+x_{jt}^{i}}
z3i⩽j=1∑Nxtji+xjti
决策所产生的资金变化:
a.挖矿收益:
r
i
=
{
0
1000
z
2
i
=
1
z
2
i
=
0
r_i=\left\{ \begin{array}{c} 0\\ 1000\\ \end{array} \right. \begin{array}{c} z2_i=1\\ z2_i=0\\ \end{array}
ri={01000z2i=1z2i=0
b.物资购买为初始地的两倍价格。
最后得出的每天资金减少量为:
c
l
o
s
s
i
=
10
c
X
i
+
20
c
Y
i
−
r
i
closs_i=10cX_i+20cY_i-r_i
clossi=10cXi+20cYi−ri
剩余资金:
r
e
w
a
r
d
i
=
10000
−
c
o
s
t
−
∑
q
=
1
i
−
1
c
l
o
s
s
q
reward_i=10000-cost-\sum_{q=1}^{i-1}{closs_q}
rewardi=10000−cost−∑q=1i−1clossq
决策后所剩余的水和食物必须充足,满足生存条件,同时资金限制和重量限制也需要满足:
10000
−
c
o
s
t
−
∑
q
=
1
i
−
1
c
l
o
s
s
q
⩾
c
l
o
s
s
i
1200
−
w
e
i
g
h
t
−
∑
q
=
1
i
−
1
w
l
o
s
s
q
⩾
w
l
o
s
s
i
\\ 10000-cost-\sum_{q=1}^{i-1}{closs_q}\geqslant closs_i \\ 1200-weight-\sum_{q=1}^{i-1}{wloss_q}\geqslant wloss_i
10000−cost−q=1∑i−1clossq⩾clossi1200−weight−q=1∑i−1wlossq⩾wlossi
每天水和食物的消耗量计算公式:
y
X
i
=
{
p
i
b
i
0
未抵达终点
抵达终点
y
Y
i
=
{
q
i
b
i
0
未抵达终点
抵达终点
yX_i=\left\{ \begin{array}{c} p_ib_i\\ 0\\ \end{array} \right. \,\,\begin{array}{c} \,\,\text{未抵达终点}\\ \text{抵达终点}\\ \end{array}\,\,yY_i=\left\{ \begin{array}{c} q_ib_i\\ 0\\ \end{array} \right. \begin{array}{c} \,\,\text{未抵达终点}\\ \text{抵达终点}\\ \end{array}
yXi={pibi0未抵达终点抵达终点yYi={qibi0未抵达终点抵达终点
其中倍数
b
i
b_i
bi的计算公式为:
b
i
=
{
1
2
3
停留
移动
挖矿
b_i=\left\{ \begin{array}{c} 1\\ 2\\ 3\\ \end{array} \right. \begin{array}{c} \text{停留}\\ \text{移动}\\ \text{挖矿}\\ \end{array}
bi=⎩⎨⎧123停留移动挖矿
4.目标函数:
剩余物资半价回收处理:
max
f
=
r
e
w
a
r
d
30
+
5
f
o
o
d
30
+
2.5
w
a
t
e
r
30
\max f=reward_{30}+5food_{30}+2.5water_{30}
maxf=reward30+5food30+2.5water30
LINGO编程求解:
model:
sets:
a1/1..27/;
a2(a1,a1):d;
!d是由题目给出的拓扑图所获得的相邻矩阵关系,d(j,k)=1表示区域j和k相邻,否则不相邻;
a3/1..30/:cX,cY,yY,yX,w,z1,z2,z3,b,r,aX,aY,kk,wuzi,shui;
!cX cY是村庄购买食物和水的量,yX,yY是食物和水对应天气所需要的消耗量,w代表天气 1 2 3分别为晴朗、高温和沙暴;
!z1,z2,z3代表移动、挖矿、购买的决策变量,b是z1、z2、z3决策所造成的倍数:移动是2 停留是1 挖矿是3,r是挖矿收益,若挖矿则收益为1000,aX、aY每天食物和水的消耗量;
!kk代表剩余资金,wuzi为剩余食物,shui剩余水;
a4(a3,a1,a1):x;!x(i,j,k)=1表示第i天从j点去往k点;
a5(a3,a1);
endsets
x1>0;
y1>0;
@gin(x1);
@gin(y1);
!起始点购买水和物资的数量大于0且为整数;
@for(a3(i):@bin(z1(i)));
@for(a3(i):@bin(z2(i)));
@for(a3(i):@bin(z3(i)));
!行动决策变量为0-1变量,z1=1表示停留 0作移动,z2=1表示挖矿 0则不挖矿,z3=1表示途径村落购买物资,0则不买物资;
@for(a3(i):@gin(cX(i)));
@for(a3(i):@gin(cY(i)));
@for(a3(i):cX(i)>=0);
@for(a3(i):cY(i)>=0);
!购买食物和水的数量必须大于0且为整数;
!各变量约束;
weight=3*x1+2*y1;
cost=5*x1+10*y1;
cost<=10000;
weight<=1200;
!初始约束,重量和资金约束;
@for(a4(i,j,k):x(i,j,k)<=d(j,k));
!只走接壤 只有d(j,k)=1时候,x(i,j,k)才可以为1,因此x严格小于等于d;
@for(a4(i,j,k):@bin(x(i,j,k)));
!整数规划;
@for(a3(i):@sum(a2(j,k):x(i,j,k))=1);
!每天一决策 对j k求和 对于所有的i x(i,j,k)仅有一个为1;
@sum(a1(k):x(1,1,k))=1;
!起点出发 第一天从1处去往k点,若k=1则为停留;
@sum(a5(i,j)|j#ne#27:x(i,j,27))=1;
!有一天走去终点,必然从不等于27的区域去往27 27是第一问题目的终点;
@for(a3(i)|i#ne#30:x(i+1,27,27)=@sum(a1(j):x(i,j,27)));
!到达终点停止,若到达终点,未满30天,后面的天数则视为在27处停留,不消耗物资,资金数也不发生变化;
@for(a5(i,j)|i#ne#30:@sum(a1(k):x(i+1,j,k))=@sum(a1(k):x(i,k,j)));
!当天出发=前一天目的地,保持移动路径连续;
@for(a3(i):z1(i)=@sum(a1(j):x(i,j,j)));
!是否停留;
@for(a3(i):w(i)-@sum(a1(j):x(i,j,j))<=2);
!沙暴必须停留 w=3 @sum(a1(j):x(i,j,j))必须为1进行停留 w=1或者2时候@sum(a1(j):x(i,j,j))可以为0或者1;
@for(a3(i):cX(i)<=1000*z3(i));
!购买食物条件,只有z3=1时可以购买物资,姑且设1000为数量上限;
@for(a3(i):cY(i)<=1000*z3(i));
!购买水条件,同样只有z3=1时可以购买物资,姑且设1000为数量上限;
@for(a3(i):r(i)=1000*z2(i));
!挖矿条件 z2=1了,才会有收益;
@for(a3(i):10*cX(i)+20*cY(i)<=10000-cost-@sum(a3(j)|j#lt#i:10*cX(j)+20*cY(j)-r(j)));
!资金限制,(第i天购买水和食物的资金)必须小于(总资金-初始购买所花资金-前面所有天历史花费的资金+历史挖矿所得资金);
@for(a3(i):3*cX(i)+2*cY(i)<=1200-weight-@sum(a3(j)|j#lt#i:3*cX(j)+2*cY(j)-3*yX(j)-2*yY(j)));
!重量限制,(第i天购买水和食物的重量)必须小于(总重量-初始购买的水和食物的重量-前面所有天消耗的水和食物的重量+前面所有天历史购买的水和食物的重量);
@for(a3(i):yX(i)=aX(i)*b(i));
@for(a3(i):yY(i)=aY(i)*b(i));
!消耗量函数 总消耗量=单位消耗量决策倍数;
@for(a3(i):b(i)=2+2*z2(i)-z1(i)-x(i,27,27));
!消耗量关于天气 决策的函数关系 b表示倍数 挖矿3倍 移动2倍 停留1倍 如果抵达终点在终点停留为0倍;
@for(a3(i):z2(i)<=x(i,12,12));
@for(a3(i):z3(i)<=@sum(a1(j):x(i,j,15)+x(i,15,j)));
!挖矿 购买 决策约束条件 挖矿必须在矿山12处作停留 购买物资必须途径村庄15;
max=kk(30)+2.5*shui(30)+5*wuzi(30);
!目标函数;
@for(a3(i):kk(i)=10000-cost-@sum(a3(j)|j#lt#i:10*cX(j)+20*cY(j)-r(j))+r(i));
!剩余总资金;
@for(a3(i):shui(i)=x1-@sum(a3(j)|j#lt#i:yX(j)-cX(j))-yX(i));
@for(a3(i):wuzi(i)=y1-@sum(a3(j)|j#lt#i:yY(j)-cY(j))-yY(i));
!剩余水和食物必须大于0;
@for(a3(i):wuzi(i)>=0);
@for(a3(i):shui(i)>=0);
@for(a3(i):aX(i)=@if(w(i)#eq#1,5,@if(w(i)#eq#2,8,10)));
@for(a3(i):aY(i)=@if(w(i)#eq#1,7,@if(w(i)#eq#2,6,10)));
data:
w=2 2 1 3 1 2 3 1 2 2 3 2 1 2 2 2 3 3 2 2 1 1 2 1 3 2 1 1 2 2;
@text('data.txt')=@write('最大资金数为',kk(30)+2.5*shui(30)+5*wuzi(30),'元 行走路径为:',@newline(1));
@text('data.txt')=@writefor(a4(i,j,k)|x(i,j,k)#eq#1 #and# x(i,27,27)#eq#0:'第',i,'天','从',j,'点去往',k,'点,','消耗水',yX(i),'个,食物',yY(i),'个,剩余水',shui(i),'个,食物有',wuzi(i),'个;',@newline(1));
@text('data.txt')=@writefor(a3(i)|@sum(a1(j):x(i,j,27))#eq#1 #and# x(i,27,27)#eq# 0:'在第',i,'天抵达终点。',@newline(1));
@text('data.txt')=@writefor(a3(i)|z2(i)#eq#1:'在第',i,'天选择挖矿',@newline(1));
@text('data.txt')=@writefor(a3(i)|z3(i)#eq#1:'在第',i,'天从村落里购买了',cX,'个食物和',cY,'个水',@newline(1));
d=
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1
0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 0
0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0
1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1;
enddata
end
LINGO求解结果:
第一问通过LINGO@text{}输出结果如下:
最大资金数为10470元 行走路径为:
第1天从1点去往25点,消耗水16个,食物12个,剩余水162个,食物有321个;第2天从25点去往24点,消耗水16个,食物12个,剩余水146个,食物有309个;第3天从24点去往23点,消耗水10个,食物14个,剩余水136个,食物有295个;第4天从23点去往23点,消耗水10个,食物10个,剩余水126个,食物有285个;第5天从23点去往22点,消耗水10个,食物14个,剩余水116个,食物有271个;第6天从22点去往9点,消耗水16个,食物12个,剩余水100个,食物有259个;第7天从9点去往9点,消耗水10个,食物10个,剩余水90个,食物有249个;第8天从9点去往15点,消耗水10个,食物14个,剩余水80个,食物有235个;第9天从15点去往14点,消耗水16个,食物12个,剩余水64个,食物有223个;第10天从14点去往12点,消耗水16个,食物12个,剩余水211个,食物有211个;第11天从12点去往12点,消耗水10个,食物10个,剩余水201个,食物有201个;第12天从12点去往12点,消耗水24个,食物18个,剩余水177个,食物有183个;第13天从12点去往12点,消耗水15个,食物21个,剩余水162个,食物有162个;第14天从12点去往12点,消耗水24个,食物18个,剩余水138个,食物有144个;第15天从12点去往12点,消耗水24个,食物18个,剩余水114个,食物有126个;第16天从12点去往12点,消耗水24个,食物18个,剩余水90个,食物有108个;第17天从12点去往12点,消耗水30个,食物30个,剩余水60个,食物有78个;第18天从12点去往12点,消耗水10个,食物10个,剩余水50个,食物有68个;第19天从12点去往12点,消耗水24个,食物18个,剩余水26个,食物有50个;第20天从12点去往13点,消耗水16个,食物12个,剩余水10个,食物有38个;第21天从13点去往15点,消耗水10个,食物14个,剩余水0个,食物有24个;第22天从15点去往9点,消耗水10个,食物14个,剩余水0个,食物有26个;第23天从9点去往21点,消耗水16个,食物12个,剩余水10个,食物有14个;第24天从21点去往27点,消耗水10个,食物14个,剩余水0个,食物有0个;在第24天抵达终点。
在第12天选择挖矿,在第13天选择挖矿,在第14天选择挖矿,在第15天选择挖矿,在第16天选择挖矿,在第17天选择挖矿,在第19天选择挖矿
在第9天从村落里购买了163个食物和0个水
在第21天从村落里购买了10个食物和16个水
在第22天从村落里购买了26个食物和0个水
建立的模型均是ILP,求解速度都很快。
第二问代码见:https://download.csdn.net/download/Xialiuto/79002543