本文主要是介绍数学建模--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,32,4 2,5 2,63,4 3,5 3,64,7 4,85,7 5,8 5,96,8 6,9 7,108,109,10/:W, P;
endsets
data:
W = 6 53 6 97 5 119 18 7 5 4 10579;enddatan = @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;
endsetsdata:
T = 6 2 6 7 4 2 54 9 5 3 8 5 85 2 1 9 7 4 37 6 7 3 9 2 72 3 9 5 7 2 65 5 2 2 8 11 49 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;
endsetsdata:
c = 5 8 10 6 9 5 7 6 10 8;
enddatamin = @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;
endsetsdata:
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;
enddatamin = @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;
endsetsdata:
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;
enddatainit:
x = 5 2;
y = 1 7;
endinitmin = @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);
endsetsdata:
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;
enddatainit:
a = 0;
b = 0;
endinitmin = @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;
endsetsmax = 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;
endsetsdata:
c1 = 1 1 3 4 2;
c2 = -8 -2 -3 -1 -2;
a = 1 1 1 1 11 2 2 1 62 1 6 0 00 0 1 1 5;
r = 400 800 200 200;
enddatamax = @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
这篇关于数学建模--Lingo语言使用总结以及经典例题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!