Lingo学习心得&2014年研究生数模竞赛E题

0 前言

2023/10/14:增加代码说明、参考资料;
2015/08/25:首次发布;

非常感慨,这篇文章距离我再次修改竟然已经是八年之后了。八年前的那个大二结束后的暑假,我留校参加了数学建模竞赛的集训,在这道题的训练中,我学会了使用Lingo去解决一些最优化的问题,于是就将学习的笔记和对这道题的解题思路发表了在了博客上。时过境迁,其中的一些细节我自己都有些模糊,更何论是访问这篇文章的同学。因此我决定再优化一下这篇博客,希望能给之后访问到这篇博客的同学一些帮助。本文的思路也不一定对,仅供大家参考。

参考资料:

1 题目介绍

第四次数模培训,2014年研究生数学建模竞赛E题:乘用车物流运输计划问题。

“轿运车”是通过公路来运输乘用车整车的专用运输车,根据型号的不同有单层和双层两种类型,由于单层轿运车实际中很少使用,本题仅考虑双层轿运车。双层轿运车又分为三种子型,每辆轿运车可以装载乘用车的最大数量在6到27辆之间。

  • 上下层各装载1列乘用车,故记为1-1型(图1):
    图1:1-1型轿运车
  • 下、上层分别装载1、2列,记为1-2型(图2):
    图2:1-2型轿运车
  • 上、下层各装载2列,记为2-2型(图3):
    图3:2-2型轿运车

在确保完成运输任务的前提下,物流公司追求降低运输成本。但由于轿运车、乘用车有多种规格等原因,当前很多物流公司在制定运输计划时主要依赖调度人员的经验,在面对复杂的运输任务时,往往效率低下,而且运输成本不尽理想。请你们为物流公司建立数学模型,给出通用算法和程序(评审时要查)。

装载具体要求如下:每种轿运车上、下层装载区域均可等价看成长方形,各列乘用车均纵向摆放,相邻乘用车之间纵向及横向的安全车距均至少为0.1米,下层力争装满,上层两列力求对称,以保证轿运车行驶平稳。受层高限制,高度超过1.7米的乘用车只能装在1-1、1-2型下层。轿运车、乘用车规格(第五问见附件)如下:

  • 乘用车规格
乘用车型号长度(米)宽度(米)高度(米)
4.611.71.51
3.6151.6051.394
4.631.7851.77
  • 轿运车规格
轿运车类型上下层长度(米)上层宽度(米)下层宽度(米)
1-1192.72.7
1-224.33.52.7

整车物流的运输成本计算较为繁杂,这里简化为:

  • 影响成本高低的首先是轿运车使用数量;
  • 其次,在轿运车使用数量相同情况下,1-1型轿运车的使用成本较低,2-2型较高,1-2型略低于前两者的平均值,
  • 但物流公司1-2型轿运车拥有量小,为方便后续任务安排,每次1-2型轿运车使用量不超过1-1型轿运车使用量的20%;
  • 再次,在轿运车使用数量及型号均相同情况下,行驶里程短的成本低,注意因为该物流公司是全国性公司,在各地均会有整车物流业务,所以轿运车到达目的地后原地待命,无须放空返回。最后每次卸车成本几乎可以忽略。

前三问:
1. 物流公司要运输Ⅰ车型的乘用车100辆及Ⅱ车型的乘用车68辆。
2. 物流公司要运输Ⅱ车型的乘用车72辆及Ⅲ车型的乘用车52辆。
3. 物流公司要运输Ⅰ车型的乘用车156辆、Ⅱ车型的乘用车102辆及Ⅲ车型的乘用车39辆。

要求制定详细计划,含所需要各种类型轿运车的数量、每辆轿运车的乘用车装载方案、行车路线。(前三问目的地只有一个,可提供一个通用程序)

2 解决方案

2.1 使用matlab将每种轿用车的满载方案求出来

I-I型轿用车:

clear all;
clc;

% 1-1车型上层只能装1,2型车
m = 1;
for a = 0:4    %1型车,最多装4辆
    for b = 0:5 %2型车,最多装5辆
        % 满装策略,1,2型乘用车总长小于1-1型车且剩余空间无法放下一辆2型车(2型车最短)
        if (19- (a*4.71+b*3.715) ) <= 3.715&&(a*4.71+b*3.715)<=19
            Up(m,1) = a;
            Up(m,2) = b;
            Up(m,3) = 0;
            m = m + 1;
        end
    end
end

% 1-1车型下层可以装1,2,3型车
n = 1;
for a= 0:4          %1型车,最多装4辆
    for b = 0:5     %2型车,最多装5辆
        for c = 0:4 %3型车,最多装4辆
            % 满装策略,1,2型乘用车总长小于1-1型车且剩余空间无法放下一辆2型车(2型车最短)
            if (a*4.71+b*3.715+c*4.73)<=19&&(19-(a*4.71+b*3.715+c*4.73))<=3.715
                Down(n,1) = a;
                Down(n,2) = b;
                Down(n,3) = c;
                n = n +1;
            end
        end
    end
end

% 上下层结果统计
k = 1;
for i = 1:(m-1)
    for j = 1:(n-1)
        % 1型车的装载情况
        Total(k,1) = Up(i,1)+Down(j,1); 
        % 2型车的装载情况
        Total(k,2) = Up(i,2)+Down(j,2);
        % 3型车的装载情况
        Total(k,3) = Up(i,3)+Down(j,3);
        k = k + 1;
    end
end

这里算出来一共有(m-1) x (n-1) = 75种方案,将每种方案1,2,3型车的装在情况写在一个txt中,每行一个数字,1,2,3型乘用车之间用~隔开,如下所示:

!1-1,1型号车装载情况:
1
2

~
!1-1,2型号车装载情况:
1
2

~
!1-1,3型号车装载情况:
1
2

~

I-II型轿用车

clear all;
clc;
% 1-2车型下层满装策略
m = 1;
for a=0:5           %1型车,最多装5辆
    for b=0:6       %2型车,最多装6辆
        for c=0:5   %3型车,最多装5辆
            % 满装策略,车总长小于1-2型车长度且剩余空间无法放下一辆2型车(2型车最短)
            if (a*4.71+b*3.715+c*4.73)<=24.3&&(24.3-(a*4.71+b*3.715+c*4.73))<=3.715
                Down(m,1)=a;
                Down(m,2)=b;
                Down(m,3)=c;
                m = m + 1;
            end
        end
    end
end

% 1-2车型上层满装策略
n =1;
for a=0:5      %1型车,最多装5辆
    for b=0:6  %2型车,最多装6辆
            % 单列满装策略,车总长小于1-2型车长度且剩余空间无法放下一辆2型车(2型车最短)
            if (a*4.71+b*3.715)<=24.3&&(24.3-(a*4.71+b*3.715))<=3.715
                Up(n,1)=2*a;
                Up(n,2)=2*b;
                Up(n,3) = 0;
                n = n + 1;
            end       
    end
end


k = 1;
for i = 1:(n-1)
    for j = 1:(m-1)
        % 1型车的装载情况
        Total(k,1) = Up(i,1)+Down(j,1);
        % 2型车的装载情况
        Total(k,2) = Up(i,2)+Down(j,2);
        % 3型车的装载情况
        Total(k,3) = Up(i,3)+Down(j,3);
        k = k + 1;
    end
end

与1-1一样,将1,2,3类型的乘用车的装载情况写入txt中,并用~隔开。

2.2 使用Lingo进行线性规划

代码如下

model:
	sets:
		!1-1型车装载方案,共75个:x1,y1,z1分别代表每种方案123型车的装载数量;
		YI/1..75/:x1,y1,z1,m;
		!1-2型车装载方案,共13个:x2,y2,z2分别代表每种方案123型车的装载数量;
		ER/1..132/:x2,y2,z2,n;
	endsets
	
	data:
		x1 = @file('1-1.txt');
		y1 = @file('1-1.txt');
		z1 = @file('1-1.txt');
	
		x2 = @file('1-2.txt');
		y2 = @file('1-2.txt');
		z2 = @file('1-2.txt');
	enddata
	
	!第一问: 运输Ⅰ车型的乘用车100辆及Ⅱ车型的乘用车68;
	@sum(YI(I):x1(I)*m(I))+@sum(ER(J):x2(J)*n(J)) >= 100;
	@sum(YI(I):y1(I)*m(I))+@sum(ER(J):y2(J)*n(J)) >= 68;
	!第二问: Ⅱ车型的乘用车72辆及Ⅲ车型的乘用车52;
	!@sum(YI(I):x1(I)*m(I))+@sum(ER(J):x2(J)*n(J)) = 0;
	!@sum(YI(I):y1(I)*m(I))+@sum(ER(J):y2(J)*n(J)) >= 72;
	!@sum(YI(I):z1(I)*m(I))+@sum(ER(J):z2(J)*n(J)) >= 52;
	!第三问: Ⅰ车型的乘用车156辆、Ⅱ车型的乘用车102辆及Ⅲ车型的乘用车39;
	!@sum(YI(I):x1(I)*m(I))+@sum(ER(J):x2(J)*n(J)) >= 156;
	!@sum(YI(I):y1(I)*m(I))+@sum(ER(J):y2(J)*n(J)) >= 102;
	!@sum(YI(I):z1(I)*m(I))+@sum(ER(J):z2(J)*n(J)) >= 39;
	
	!1-2车的数量不超过1-120;
	@sum(ER(I):n(I)) <= 0.2*@sum(YI(J):m(J));
	!最小化乘用车数量;
	min = @sum(ER(I):n(I)) + @sum(YI(J):m(J));
	!限制m,n为正整数,表示每种方案的数量;
	@for(YI:@gin(m));
	@for(ER:@gin(n));

end

3 Lingo学习的总结

3.1 集的理解

sets:
    YI/1..75/:x1,y1,z1,m;
    ER/1..132/:x2,y2,z2,n;
endsets

在sets 和 endsets命令中设置集,集给人的体验就是首先有一个集的名称,紧接着在集名称后面接上/ /,双斜杠中的内容称之为集的成员,接上后就是集的属性,这样一个集就生成了。
其感觉就像是集的属性相当于几个数组,而数组的大小就是集成员的大小,而且这个数组的地址不是数字,就是集的成员,比如集的成员为/mon..sun/,那么这个集的属性A就是A[mon]~A[sun]

3.2 Lingo中数据的定义

data:
	x1 = @file('1-1.txt');
	y1 = @file('1-1.txt');
	z1 = @file('1-1.txt');

	x2 = @file('1-2.txt');
	y2 = @file('1-2.txt');
	z2 = @file('1-2.txt');
enddata

在lingo中数据的定义是在data: 和 enddata中完成的,数据的内容基本上是集的属性,在上述例子中我用到了一个@file函数,这个函数就是lingo中的读取文本文件的函数,其用法就是@file(‘文件地址\文件名.txt’),在txt中的数据要用~分开。其意思就是说我每读取一次文件,读取到~位置就停止,当下一次读取这个文件的时候,从上次的~读取到下次的~之间的数据。

3.3 @sum的使用

@sum函数一般使用在求和上,其用法就是@sum(集名:要求和的函数)。
其中,如果是对这个集中某个属性的部分数据进行求和,那么可以在集名后加上或符号再跟上你要约束的条件,即:集名|约束条件

3.4 @for的使用

@for函数一般用于约束条件的定义,如果约束条件过多,且具有一定的相似性,那么就可以中@for函数来声明。使用案例:

@for(YI:@gin(m));

比如上述的代码中,YI代表你要循环声明的集,或者是范围,跟上,后面接上你要循环的内容,在上述的代码中我的意思就是声明YI这个集的属性m全为整数。

3.5 @gin

限制变量只能为正整数。

  • 7
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值