數學建模--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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章