数学建模--Lingo语言使用总结以及经典例题

准备数学建模比赛中,使用的是Lingo软件,将学习中遇到的问题做下总结:

资料总结链接:https://blog.csdn.net/yzu_120702117/article/details/38415153

1、关于数学函数使用过程的问题
model:
sets:
object/1 .. 3/: f;
endsets
data:
a, b = 3, 4;
x = ?;
enddata
@free(x);
f(1) = a*@sin(x);
f(2) = b*@cos(x);
f(3) = a*@sin(x) + b*@cos(x);
y = @smax(f(1), f(2), f(3));
end

思路:建立集合,并将函数值保存到每个成员中的 f 中。
目的:练习使用集合以及常用函数。
遇到的问题:每次输入大于1.57(这是弧度,对应的角度就是大于90),就报错如下:
        在这里插入图片描述

意思就是说:f (2)的式子约束太多,不能表示出来,请减少变量约束;
其实也很好理解,当大于90时,cos(x)是小于0的,这时候就不能正常表示,需要free ( f ),让f可以为任意数。
代码加一句@for(object(i): @free(f(i)));即可(这是针对集合的语句呦)。

2、关于经典例题–职员时序安排问题求解思路

题目:职员时序安排模型 一项工作一周七天都需要有人,每天(周一至周日)所需的最少职员数位20,16,13,19,14和12,并要求每个职员一周连续工作5天,试求每周所需最少的职员数,并给出安排。注意这里我们考虑稳定后的情况。

  • 按照决策变量,目标函数,约束条件的思路从题目中提取相关信息。
    ① 根据一周连续工作5天,设决策变量为从周x开始的员工。(我用集合来表示:n(1)为周一开始工作的员工数目,…n(7)为周日开始工作的员工数目)
    ② 根据最少的职员数,确定木匾函数为n(1) + … + n(7)的最小值。
    ③ 根据最少职员数位20,16,13,19,14和12,确定约束条件。

                在这里插入图片描述
N(1) + N(4) + N(5) + N(6) + N(7) >= 20;
N(1) + N(2) + N(5) + N(6) + N(7) >= 16;
N(1) + N(2) + N(3) + N(6) + N(7) >= 13;
N(1) + N(2) + N(3) + N(4) + N(7) >= 16;
N(1) + N(2) + N(3) + N(4) + N(5) >= 19;
N(2) + N(3) + N(4) + N(5) + N(6) >= 14;
N(3) + N(4) + N(5) + N(6) + N(7) >= 12;

  • 这些分析完成之后,写代码就很简单了:
model:

sets:
!决策变量:设员工周x开始工作的员工数目为n(x);
workers/1 .. 7/:n;
endsets
!员工数目为整数;
@for(workers(i): @gin(n));
!目标函数;
min = @sum(workers(i):n);
!约束条件;
n(1) + n(4) + n(5) + n(6) + n(7) >=20;
n(1) + n(2) + n(5) + n(6) + n(7) >= 16;
n(1) + n(2) + n(3) + n(6) + n(7) >= 13;
n(1) + n(2) + n(3) + n(4) + n(7) >= 16;
n(1) + n(2) + n(3) + n(4) + n(5) >= 19;
n(6) + n(2) + n(3) + n(4) + n(5) >= 14;
n(5) + n(6) + n(3) + n(4) + n(7) >= 12;

end

这是我的很直观的解法,思路没问题,就是语句繁琐,标准答案参见:
https://blog.csdn.net/m307617071/article/details/5514489#commentsedit

3、经典例题–TSP问题(旅行商问题)

题目:有一个销售员,从城市1出发,要遍访城市2,3,…,n个一次,最后返回城市1.已知从城市i到j的距离为C(ij),问他该按怎样的次序访问这些城市,是得总距离最少?
这个旅行商问题可以转换成混合整数线性规划问题(MILP)。

  • 对TSP 的数学描述:
    引入0-1 变量??? (? ≠ ?):???=1 表示路线从i 到j;???=0 表示不走i→j 这条路。
    则TSP 可表示为:

            在这里插入图片描述
上述约束条件中的前三个类似指派型问题,只是TSP 的必要条件;因此我们针对第四条约束条件用下列数学表达式来实现:
增加变量?? (? = 1,2, … , ?),并且?? − ?? + ???? ≤ ? − 1; ?? , ?? ≥ 0, ? = 1,2, … , ?, ? = 2,3, … , ?, i ≠ j.
于是TSP 问题转化成了一个混合整数线性规划模型。

决策变量:每个城市之间的距离Cij(代码中是dist表示)以及xij;
目标函数:总距离的最小值,min = @sum(link: dist * x);
约束条件:① @for(city(i):@sum(city(j) | i#ne#j:x(i, j)) = 1);
       @for(city(i):@sum(city(j) | i#ne#j:x(j, i)) = 1);!行和以及列和都是1
     ② @for(city(i):@for(city(j) | i#gt#1 #and# i#ne#j : u(i) - u(j) + n*x(i, j) <= n - 1 ) ; );!添加的额外约束
     ③ @for(link:@bin(x));!只能是0或1
分析完毕之后,写代码就很简单了。
源代码:

model:
!5个城市;
sets:
city/1 .. 5/:u;
link(city, city):dist, x;
endsets
!将距离信息放到dist文件中;
data:
dist = @file('dist.txt');
enddata
!城市的数量;
n = @size(city);

!约束条件;
!行 列和为1;
@for(city(i):
	@sum(city(j)|i#ne#j:x(i, j)) = 1;
	@sum(city(j)|i#ne#j:x(j, i)) = 1);
!新约束;
@for(city(i):
	@for(city(j)| j#gt#1 #and# i#ne#j:
	u(i) - u(j) + n*x(i, j) <= n - 1););
@for(city(i):u(i) <= n - 1);
!只能是0, 1;
@for(link: @bin(x));
!目标函数;
min = @sum(link:dist*x);
end

文件dist中内容是(我选取的是5个城市。)

              在这里插入图片描述

4、最短路径问题。(动态规划法求解)

题目:给定N个点Pi组成集合{Pi},由集合中任一点Pi到另一点Pj的距离用Cij表示,如果Pi到Pj没有弧连接,则规定Cij=正无穷大,有规定Cii=0,指定一个终点PN,要求从Pi到PN的最短路线。
假设F(i)是第i点到第N点的最短距离,那么 F(i) = min(j)(Cij + F(j));
                    F(N) = 0;

  • 原理理解之后写代码就很简单了:
    决策变量:城市之间的连接和距离W,那么就定义两个集合:
    city/1 … 10/:F;
    road(city, city)/1,2 1,3 2,4 2,5 2,6 3,4 3,5 3,6 4,7 4,8 5,7 5,8 5,9 6,8 6,9 7,10 8,10 9,10/:W,P;
    目标函数:
    @for(city(i) i#lt# n : F(i) = @min(road(i, j): W(i, j) + F(j)));
    由于没有约束条件,所以不考虑约束。
    求解P(i, j)的语句如下:
    @for(road(i, j): P(i, j) = @if(F(i) #eq# W(i, j) + F(j), 1, 0));

那么代码如下:

model:
sets:
!定义集合城市,属性是到终点的最短距离;
city/1 .. 10/:F;
!继承集合包含图的连接部分的权重W以及P(若该连接是最短路径的子集,那么P为1否则为0,是为了方便找最佳路径);
road(city, city)/
			1,2 1,3
			2,4 2,5 2,6
			3,4 3,5 3,6
			4,7 4,8
			5,7 5,8 5,9
			6,8 6,9 
			7,10
			8,10
			9,10
			/:W, P;
endsets
data:
W = 
	6 5
	3 6 9
	7 5 11
	9 1
	8 7 5 
	4 10
	5
	7
	9;

enddata

n = @size(city);
! 动态规划式子;
@for(city(i)| i#lt#n:F(i) = @min( road(i, j): W(i, j) + F(j)) );
!寻找路径;
@for(road(i, j): P(i, j) = @if(F(i) #eq# W(i, j) + F(j), 1, 0));

end
5、指派问题(分配问题)

题目:这是给n个人分配n项工作以获得最高效率的问题。第i个人完成第j项工作需要的平均时间为Cij。要求给每个人分配一项工作,并要求分配完这些工作,以使完成全部任务的总时间最小。

思路:
①决策变量:设集合person是工人,集合work是需要指派的任务,那么派生集合allocate(person, work),并加上属性Tij为第i个工人做第j个工作的时间,Aij是如果dii个工人做第j个工作,那么Aij = 1,否则Aij = 0.
②目标函数:
          在这里插入图片描述
③约束条件:
          在这里插入图片描述

那么代码就很好写了:

model:

sets:
work/1 .. 7/;
person/1 .. 7/;
allocate(person, work):T, A;
endsets

data:
T = 
	6 2 6 7 4 2 5
	4 9 5 3 8 5 8
	5 2 1 9 7 4 3
	7 6 7 3 9 2 7
	2 3 9 5 7 2 6
	5 5 2 2 8 11 4
	9 2 3 12 4 5 10;

enddata
!目标函数;
!min = @sum(@for(person(i):
			@for(work(j):T(i, j)*A(i, j))));
min = @sum(allocate(i, j): T(i, j)*A(i, j));
!约束条件;
@for(person(i):
		@sum(work(j): A(i, j)) = 1);
@for(work(i):
		@sum(person(j): A(j, i)) = 1);

@for(allocate : @bin(A));

end
6、最优选择问题。

题目: 某钻井队要从10个可供选择的井位中确定5个钻井探油,使总的钻探费用为最小。若10个井位的代号为s1,s2,…,s10,相应的钻探费用c1,c2,…,c10为5,8,10,6,9,5,7,6,10,8.并且井位选择上要满足下列限制条件:
(1) 或选择s1和s7,或选择钻探s9;
(2) 选择了s3或s4就不能选s5,或反过来也一样;
(3) 在s5,s6,s7,s8中最多只能选两个.

试建立这个问题的整数规划模型,确定选择的井位。
明显这是一个混合整数线性规划问题。

  • 思路:根据题意,确定:
    决策变量:集合 井oilplace/s1 … s10/ : c,f;包含属性价格c和是否开采f。
    目标函数:min = @sum(oilplace:c*f);费用和的最小值。
    约束条件:(s1 + s7 - 2)(s9 - 1) = 0;
          s(3)*s(5) + s(4)*s(5) = 0;
          s5 + s6 + s7 + s8 <= 2;
          @for(oilplace:@bin(f));
          @sum(oilplace: f) = 5.

核心就是将约束条件变换成程序。

代码就很简单写了:

model:

sets:
oilplace/s1 .. s10/:c, f;
endsets

data:
c = 5 8 10 6 9 5 7 6 10 8;
enddata

min = @sum(oilplace: c*f);

@sum(oilplace(i)| i#gt#4 #and# i#lt#9: f(i)) <= 2;
@sum(oilplace: f) = 5;
(f(1) + f(7) - 2)*(f(9) - 1) = 0;
!f(9) = @if(f(1)#eq#1 #and# f(7)#eq#1,  0, 1);
!f(5) = @if(f(3)#eq#1 #or# f(4)#eq#1, 0, 1);
!f(3) = @if(f(5)#eq#1, 0, 1);
!f(4) = @if(f(5)#eq#1, 0, 1);
f(3)*f(5) + f(4)*f(5) = 0;
@for(oilplace:@bin(f));

end
7、选址问题(1)

某公司有六个建筑工地,位置座标(ai,bi)(单位:公里),水泥日用量di(单位:吨)
在这里插入图片描述
(1) 现有2个料场,位于A(5,1),B(2,7),记(xj,yj),及,2,日存储量ej各有20吨。假设工地和料场之间有直线道路,制定每天的供应计划,即从A,B两料场分别向工地运送水泥,是得总的吨公里数最小,其中Cij表示i工地从j料场运来的水泥量。则可以建立模型
在这里插入图片描述
分析得到:
决策变量:工地:workplace/1 … 6/: a, b, d;
      料场 ;material/A B/:x, y, e;
      两者合集all(material, workplace):c;
目标函数:min = @sum(all(i, j):@sqrt((x(i) - a(j))^2 + (y(i) - b(j))^2)*c(i, j));
约束条件:@for(material(i):
             @sum(workplace(j):c(i, j)) <= 20);
      @for(workplace(j):
             @sum(material(i):c(i, j)) = d(j));
那么代码就很好写了:

model:

sets:
workplace/1 .. 6/:a, b, d;
material/A B/:x, y, e;
all(material, workplace): c;
endsets

data:
e = 20;
a = 1.25 8.75 0.5 5.75 3 7.25;
b = 1.25 0.75 4.75 5 6.5 7.75 ;
x = 5, 2;
y = 1, 7;
d = 3 5 4 7 6 11;
enddata

min = @sum(all(i, j):((x(i) - a(j))^2 + (y(i) - b(j))^2)^.5*c(i, j));

@for(material(i):
			@sum(workplace(j): c(i, j)) <= 20);
!c(1, 1) + c(2, 1) = 3;
!c(1, 2) + c(2, 2) = 5;
!c(1, 3) + c(2, 3) = 4;
!c(1, 4) + c(2, 4) = 7;
!c(1, 5) + c(2, 5) = 6;
!c(1, 6) + c(2, 6) = 11;

@for(workplace(j):
			@sum(material(i): c(i, j)) = d(j));
end

(2)改建两个新料场,需要确定新料场位置(xj,yj)和运量cij,在其他条件不变下使总公里数最小。模型与上面的一样,位置变量变为料场位置(xj,yj),变为非线性优化问题。
加一个init初始化就可以,给两个料场赋初值,找最近点。新代码如下:

model:

sets:
workplace/1 .. 6/:a, b, d;
material/A B/:x, y, e;
all(material, workplace): c;
endsets

data:
e = 20;
a = 1.25 8.75 0.5 5.75 3 7.25;
b = 1.25 0.75 4.75 5 6.5 7.75 ;
d = 3 5 4 7 6 11;
enddata

init:
x = 5 2;
y = 1 7;
endinit

min = @sum(all(i, j):((x(i) - a(j))^2 + (y(i) - b(j))^2)^.5*c(i, j));

@for(material(i):
			@sum(workplace(j): c(i, j)) <= 20);
!c(1, 1) + c(2, 1) = 3;
!c(1, 2) + c(2, 2) = 5;
!c(1, 3) + c(2, 3) = 4;
!c(1, 4) + c(2, 4) = 7;
!c(1, 5) + c(2, 5) = 6;
!c(1, 6) + c(2, 6) = 11;

@for(workplace(j):
			@sum(material(i): c(i, j)) = d(j));
end

8、选址问题(2)

题目:某海岛上有12个主要的居民点,每个居民点的位置(用平面座标x,y表示,单位km)和居住人数(r)如下表所示。现在准备在海岛上建一个服务中心为居民提供各种服务,那么服务中心应该建在那里?
在这里插入图片描述

这个题目没有约束变量,仅仅要一个最小值的目标函数就可以。
在这里插入图片描述

代码:

model:

sets:
live/1 .. 12/: x, y, r;
server/A/:a, b;
all(server, live);
endsets

data:
x = 0 8.20 0.50 5.70 0.77 2.87 4.43 2.58 0.72 9.76 3.19 5.55;
y = 0 0.50 4.90 5.00 6.49 8.75 3.26 9.32 9.96 3.16 7.20 7.88;
r = 600 1000 800 1400 1200 700 600 800 1000 1200 1000 1100;
enddata

init:
a = 0;
b = 0;
endinit

min = @sum(all(i, j): ((a(i) - x(j))^2 + (b(i) - y(j))^2)^.5*r(j));

end
9、非线性整数规划

在这里插入图片描述
还要求Xi是整数。

这就很明显的题目了,直接写就可以。
最显然的写法:

model:

sets:
data1/1 .. 5/:d;
endsets

max = d(1)^2 + d(2)^2 + 3*d(3)^2 + 4*d(4)^2 + 2*d(5)^2 - 8*d(1) - 2*d(2) - 3*d(3) - d(4) - 2*d(5);

!@for(data1:d >= 0);
!@for(data1:d <= 99);

d(1) + d(2) + d(3) + d(4) + d(5) <= 400;
d(1) + 2*d(2) + 2*d(3) + d(4) + 6*d(5) <= 800;
2*d(1) + d(2) + 6*d(3)  <= 200;
d(3) + d(4) +5* d(5) <= 200;
@for(data1:@gin(d));
@for(data1:@bnd(0, d, 99));
end

应用Lingo比较熟练的代码:

model:

sets:
row/1 .. 4/:r;
col/1 .. 5/:c1, c2, x;
all(row, col):a;
endsets

data:
c1 = 1 1 3 4 2;
c2 = -8 -2 -3 -1 -2;
a = 
	1 1 1 1 1
	1 2 2 1 6
	2 1 6 0 0
	0 0 1 1 5;
r = 400 800 200 200;
enddata

max = @sum(col: c1*x^2 + c2*x);

@for(row(i):
		@sum(col(j): a(i, j)*x(j)) <= r(i));
@for(col:@gin(x));
@for(col:@bnd(0, x, 99));

end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章