Python小白的数学建模课-07.选址问题
選址問題是要選擇設施位置使目標達到最優,是數模競賽中的常見題型。
小白不一定要掌握所有的選址問題,但要能判斷是哪一類問題,用哪個模型。
進一步學習 PuLP工具包中處理復雜問題的字典格式快捷建模方法。
歡迎關注『Python小白的數學建模課 @ Youcans』系列,每周持續更新
1. 選址問題
選址問題是指在某個區域內選擇設施的位置使所需的目標達到最優。選址問題也是一種互斥的計劃問題。
例如投資場所的選址:企業要在 m 個候選位置選擇若干個建廠,已知建廠費用、運輸費及 n 個地區的產品需求量,應如何進行選址。
選址問題是運籌學中經典的問題之一,選址問題在生產生活、物流、甚至軍事中都有著非常廣泛的應用,如工廠、倉庫、急救中心、消防站、垃圾處理中心、物流中心、導彈倉庫的選址等。更重要的,選址問題也是數模競賽的熱點問題。
選址是重要的長期決策,選址的好壞直接影響到服務方式、服務質量、服務效率、服務成本等,從而影響到利潤和市場競爭力,選址問題的研究有著重大的經濟、社會和軍事意義。
選址問題有四個基本要素:設施、區域、距離和優化目標。
歡迎關注『Python小白的數學建模課 @ Youcans』系列,每周持續更新
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.數據導入
Python小白的數學建模課-03.線性規劃
Python小白的數學建模課-04.整數規劃
Python小白的數學建模課-05.0-1規劃
Python小白的數學建模課-06.固定費用問題
Python小白的數學建模課-07.選址問題
Python小白的數學建模課-09.微分方程模型
Python小白的數學建模課-10.微分方程邊值問題
Python小白的數學建模課-12.非線性規劃
Python小白的數學建模課-15.圖論的基本概念
Python小白的數學建模課-16.最短路徑算法
Python小白的數學建模課-17.條件最短路徑算法
1.1 設施
選址問題加粗樣式中所說的設施,在具體題目中可以是工廠、倉庫、服務站等形式。
1.2 區域
選址問題中所說的區域,在具體題目中可以是工廠、車間的內部布局,也可以是給定的某個地區、甚至空間范圍。
按照規劃區域的特征,可以分為連續選址問題和離散選址問題。連續選址問題,設施可以布局在區域內的任意位置,就要求出最優選址的坐標;離散選址問題,只能從若干候選位置中進行選擇,運籌學中的選址問題通常是這類離散選址問題。
1.3 距離
選址問題中所說的距離,是指設施到服務對象之間的距離,在具體題目中也可以是某個選址位置的服務時間、成本、覆蓋范圍。如果用圖論方法求解,通常就是連接頂點的邊的權值。
當問題所關注的是設施到服務對象之間的距離時,如果問題給出的不是頂點之間的距離,而是設施的位置坐標,要注意不是只有歐式距離,對于不同問題也可能是球面距離、曼哈頓距離、切比雪夫距離。
1.4 優化目標
選址問題要求選擇最好的選址位置,但選址位置只是決策變量,選擇的最終目的通常是實現加權距離最短、費用最小、利潤最大、時間最短,這才是優化問題的目標函數。
按照目標函數的特點,可以分為:中位問題,要求總成本最小;中心問題,服務于每個客戶的最大成本最小;反中心問題:服務于每個客戶的最小成本最大。
2. 常見選址問題及建模
2.1 P-中位問題(P-median problem)
P-中位問題,假設有 N 個候選服務站和 M 個需求點,要從 N 個候選服務站中選擇 P 個,使所有需求點到最近的服務站的加權距離 dijd_{ij}dij? 的總和最小。需求點 i 的權值,通常是指該需求點的需求量。
這是一個 MinSum 問題,定義決策變量 xjx_jxj? 為選中的服務站,yijy_{ij}yij? 將各需求點匹配到最近的服務站:
xj={1,服務站j被選中0,服務站j未被選中x_j = \begin{cases} 1,& 服務站\ j\ 被選中\\ 0,& 服務站\ j\ 未被選中 \end{cases} xj?={1,0,?服務站?j?被選中服務站?j?未被選中?
yij={1,需求點i由服務站j服務0,需求點i不由服務站j服務y_{ij} = \begin{cases} 1,& 需求點\ i\ 由服務站\ j\ 服務\\ 0,& 需求點\ i\ 不由服務站\ j\ 服務 \end{cases} yij?={1,0,?需求點?i?由服務站?j?服務需求點?i?不由服務站?j?服務?
可以建立數學模型如下:
min∑i∈M∑j∈Nwidijyijs.t.:{∑j∈Nxj=P∑j∈Nyij=1,?iyij?xj≤0,?i,jxj∈{0,1},yij∈{0,1}min\;\sum_{i \in M}\sum_{j \in N} w_i d_{ij}y_{ij}\\ s.t.:\;\begin{cases} \sum_{j \in N} x_{j} = P\\ \sum_{j \in N} y_{ij} = 1,\forall i\\ y_{ij} - x_j \leq 0,\forall i,j\\ x_{j} \in \{0,1\}, \;y_{ij} \in \{0,1\} \end{cases} mini∈M∑?j∈N∑?wi?dij?yij?s.t.:??????????∑j∈N?xj?=P∑j∈N?yij?=1,?iyij??xj?≤0,?i,jxj?∈{0,1},yij?∈{0,1}?
其中:j 為服務站,i 為需求點,wiw_iwi? 為需求點 i 的需求量, dijd_{ij}dij? 為需求點 i 到服務站 j 的距離。
2.2 P-中心問題
P-中心問題,假設有 N 個候選服務站和 M 個需求點,要從 N個候選服務站中選擇 P個,使任一需求點到最近的服務站的最大距離最小。
這是一個 MinMax 問題,需要最小化任何需求點與其鄰近設施點的最大距離。P-中位問題追求總和最小,可以理解為發展經濟總量優先;P-中心問題關注最差個體的最好結果,可以理解為優先進行扶貧。
定義決策變量 xjx_jxj? 為選中的服務站,yijy_{ij}yij? 將各需求點匹配到最近的服務站:
xj={1,服務站j被選中0,服務站j未被選中x_j = \begin{cases} 1,& 服務站\ j\ 被選中\\ 0,& 服務站\ j\ 未被選中\end{cases} xj?={1,0,?服務站?j?被選中服務站?j?未被選中?
yij={1,需求點i由服務站j服務0,需求點i不由服務站j服務y_{ij} = \begin{cases} 1,& 需求點\ i\ 由服務站\ j\ 服務\\ 0,& 需求點\ i\ 不由服務站\ j\ 服務\end{cases} yij?={1,0,?需求點?i?由服務站?j?服務需求點?i?不由服務站?j?服務?
可以建立數學模型如下:
minDs.t.:{∑j∈Nwidijyij≤D,?i∑j∈Nxj=P∑j∈Nyij=1,?iyij?xj≤0,?i,jxj∈{0,1},yij∈{0,1}min\; D\\ s.t.:\;\begin{cases} \sum_{j \in N} w_i d_{ij} y_{ij} \leq D, \forall i\\ \sum_{j \in N} x_{j} = P\\ \sum_{j \in N} y_{ij} = 1, \forall i\\ y_{ij} - x_j \leq 0, \forall i,j\\ x_{j} \in \{0,1\}, \;y_{ij} \in \{0,1\} \end{cases} minDs.t.:????????????????∑j∈N?wi?dij?yij?≤D,?i∑j∈N?xj?=P∑j∈N?yij?=1,?iyij??xj?≤0,?i,jxj?∈{0,1},yij?∈{0,1}?
其中:j 為服務站,i 為需求點, dijd_{ij}dij? 為需求點 i 到服務站 j 的距離。如果只求需求點到最近的服務站的最大距離,則 wi=1w_i = 1wi?=1 ;如果要求任一需求點到最近的服務站的最大運費,則 wiw_iwi? 為需求點 i 的需求量,即加權最大距離。
2.3 集合覆蓋問題
覆蓋模型適用于一些特殊場景,例如消防中心、救護車、巡邏車等應急設施的區位選址問題。覆蓋問題分為集合覆蓋問題(Set covering problem)和最大覆蓋問題(Maximal covering problem)。
集合覆蓋問題研究滿足覆蓋所有需求點顧客的前提下,服務站的最少個數或建設費用最小的問題。假設有 N 個候選服務站和 M 個需求點,已知每個服務站的服務范圍(或服務容量),要從 N個候選服務站中選擇若干個,使所有需求點得到服務(到所屬服務站的距離或時間小于給定的臨界值),服務站的個數最少或成本最小。
定義參數 aija_{ij}aij? 為每個服務站的覆蓋范圍:
aij={1,服務站j可以覆蓋需求點i0,服務站j不能覆蓋需求點ia_{ij} = \begin{cases} 1,& 服務站\ j\ 可以覆蓋需求點\ i\\ 0,& 服務站\ j\ 不能覆蓋需求點\ i \end{cases} aij?={1,0,?服務站?j?可以覆蓋需求點?i服務站?j?不能覆蓋需求點?i?
定義決策變量 xjx_jxj? 為選中的服務站:
xj={1,服務站j被選中0,服務站j未被選中x_j = \begin{cases} 1,& 服務站\ j\ 被選中\\ 0,& 服務站\ j\ 未被選中\end{cases} xj?={1,0,?服務站?j?被選中服務站?j?未被選中?
可以建立數學模型如下:
min∑j∈Ncjxjs.t.:{∑j∈Nixj≥1,?i∈Mxj∈{0,1}min\; \sum_{j \in N} c_j x_{j}\\ s.t.:\;\begin{cases} \sum_{j \in N_i} x_j \geq 1, \forall i \in M\\ x_{j} \in \{0,1\} \end{cases} minj∈N∑?cj?xj?s.t.:{∑j∈Ni??xj?≥1,?i∈Mxj?∈{0,1}?
其中:j 為服務站,i 為需求點,cjc_jcj? 為服務站 j 的建設費用(最少個數問題中不需要考慮),Ni={j:aij=1}N_i=\{j:a_{ij}=1\}Ni?={j:aij?=1} 是覆蓋需求點 i 的候選服務站的集合。
2.4 最大覆蓋問題
最大覆蓋問題研究在已知服務站的數目和服務半徑的條件下,如何設立 P個服務站使得可接受的服務需求最大的問題。
定義決策變量 xjx_jxj? 為選中的服務站:
xj={1,服務站j被選中0,服務站j未被選中x_j = \begin{cases} 1,& 服務站\ j\ 被選中\\ 0,& 服務站\ j\ 未被選中 \end{cases} xj?={1,0,?服務站?j?被選中服務站?j?未被選中?
KaTeX parse error: Undefined control sequence: \ at position 57: …,& 需求點\ i\ 未被覆蓋\? ?\end{cases}
可以建立數學模型如下:
max∑i∈Niwizis.t.:{zi≤∑j∈Nixj,?i∈M∑j∈Mxj=pxj∈{0,1},zi∈{0,1}max\; \sum_{i \in N_i} w_i z_i\\ s.t.:\; \begin{cases} z_i \leq \sum_{j \in N_i} x_j , \forall i \in M\\ \sum_{j \in M} x_j = p\\ x_{j} \in \{0,1\}, z_{i} \in \{0,1\} \end{cases} maxi∈Ni?∑?wi?zi?s.t.:??????zi?≤∑j∈Ni??xj?,?i∈M∑j∈M?xj?=pxj?∈{0,1},zi?∈{0,1}?
其中:j 為服務站,i 為需求點,wiw_iwi? 為需求點 i 的需求量。

2.5 其它選址問題
其它選址問題,在數學建模中應用相對較少,限于篇幅不能逐一介紹其數學模型。在此將各模型的特點簡要介紹,以便判斷問題的類型。
帶固定費用和容量限制的選址問題
服務站建站的固定費用和服務站的容量(能力)限制這兩個因素具有很強的實際意義,經常作為基本選址問題的深化研究課題。
無容量限制的固定費用下的選址問題,就是去掉服務站個數的約束,并將固定建站費用加到 P-中位問題的目標函數上。
選址分配問題
選址分配問題類似于 P-中位問題,有 m 個服務站需要選址,n 個已知位置的顧客分配給不同的設施,已知每個服務站的能力和每個顧客的需求,要求服務站的選址和顧客對服務站的分配,使顧客與所分配服務站的距離總和最小。
隨機選址問題
服務站的運行時間、建設成本、需求點位置、需求數量等全部或部分參數是不確定的,但服從某種隨機分布。
動態選址問題
研究未來若干時間段內服務站的最優選址問題,在不同時間段內動態選址模型的參數是變化的,但在某一時間段內模型參數是確定的。
競爭選址問題
研究考慮市場上存在兩個以上同類產品或服務的提供者,或服務站提供多個產品或服務。
2.6 選址問題的求解算法與編程實現
設施選址問題通常是是 NP 問題,不存在多項式時間算法。常用的近似解法有:
線性規劃舍入算法,相當于整數規劃問題的求解算法。首先給出原問題的整數規劃模型,然后求解相應的線性規劃松弛問題得到分數最優解,根據可行要求對分數最優解進行改造,構造原問題的整數可行解。
原始對偶算法,首先找到對偶問題的一個可行解,再根據該對偶可行解構造原始問題的整數可行解,不斷調整對偶問題的可行解,直到找到最優解為止。
局部搜索算法:給定初始可行解,定義適當的鄰域,通過引入恰當的調整策略,在鄰域中得到改進的可行解,依次迭代,直到調整策略不能改進為止
啟發式算法或隨機優化算法。
本節作為線性規劃問題系列的一篇,仍然選擇 PuLP工具包求解選址問題。很多選址問題適合用圖論方法描述和求解,這將在后續課程中進行介紹。
3. 案例 1:PuLP求解指派問題
說明:本案例是指派問題,不是選址問題。因指派問題未單獨成文,因此將該案例放在本文中。
另外,本案例給出了 PuLP 工具包使用字典方式快捷編程的使用方法,這在選址問題中是非常方便的。
3.1 游泳接力賽的指派問題
游泳隊中 A、B、C、D 四名運動員組成 4x100米混合泳接力隊,運動員各種泳姿的成績如下表所示 (單位:秒):
| A | 56 | 74 | 61 | 63 |
| B | 63 | 69 | 65 | 71 |
| C | 57 | 77 | 63 | 67 |
| D | 55 | 76 | 62 | 62 |
如何安排 A、B、C、D 四名運動員的泳姿,才最有可能取得好成績?
3.2 指派問題建模分析
引入 0-1 變量 xijx_{ij}xij?:
xi,j={0,第i人不游第j種姿勢1,第i人游第j種姿勢,i,j=1,...4x_{i,j} = \begin{cases} 0,第\;i\;人不游第\;j\;種姿勢\\ 1,第\;i\;人游第\;j\;種姿勢,i,j=1,...4 \end{cases} xi,j?={0,第i人不游第j種姿勢1,第i人游第j種姿勢,i,j=1,...4?
指派問題的數學模型就可以描述為:
minf(x)=∑i=1n∑j=1n(cijxij)s.t.:{∑j=1nxij=1,i=1,...,n∑i=1nxij=1,j=1,...,nxij=0,1,i,j=1,...,nmin\;f(x) = \sum_{i=1} ^n \sum_{j=1} ^n (c_{ij} x_{ij})\\ s.t.:\;\begin{cases} \sum_{j=1} ^n x_{ij} = 1,i=1,...,n\\ \sum_{i=1} ^n x_{ij} = 1,j=1,...,n\\ x_{ij} = 0,1,i,j=1,...,n \end{cases} minf(x)=i=1∑n?j=1∑n?(cij?xij?)s.t.:??????∑j=1n?xij?=1,i=1,...,n∑i=1n?xij?=1,j=1,...,nxij?=0,1,i,j=1,...,n?
其中:
ci,j=(56746163636965715777636755766262)c_{i,j}=\left( \begin{matrix} 56 & 74 & 61 & 63 \\ 63 & 69 & 65 & 71 \\ 57 & 77 & 63 & 67 \\ 55 & 76 & 62 & 62 \end{matrix} \right) ci,j?=?????56635755?74697776?61656362?63716762??????
3.3 指派問題模型求解的編程
模型求解,用標準模型的優化算法對模型求解,得到優化結果。模型求解的編程步驟如下:
(0)導入 PuLP庫函數
import pulp(1)定義一個規劃問題
AssignLP = pulp.LpProblem("Assignment_problem_for_swimming_relay_race", sense=pulp.LpMinimize)pulp.LpProblem 用來定義問題的構造函數。參數 sense 指定問題求目標函數的最小值/最大值 。
(2)定義決策變量
rows = cols = range(0, 4)x = pulp.LpVariable.dicts("x", (rows, cols), cat="Binary")pulp.LpVariable 用來定義決策變量的函數。參數 cat 設定變量類型,’ Binary ’ 表示 0/1 變量。
注意,指派問題、選址問題中都涉及 N*M 維矩陣變量,變量個數很多,如果逐一定義非常冗長,而且容易出錯、不便修改。本例使用 pulp.LpVariable.dicts 提供的字典格式定義了 4*4 個變量 xijx_{ij}xij?,使程序大為簡化。
(3)添加目標函數
scoreM = [[56,74,61,63],[63,69,65,71],[57,77,63,67],[55,76,62,62]]AssignLP += pulp.lpSum([[x[row][col]*scoreM[row][col] for row in rows] for col in cols])本例程在語句內使用兩重 for 循環遍歷列表實現所有變量的線性組合 ,使程序大為簡化。
(4)添加約束條件
for row in rows:AssignLP += pulp.lpSum([x[row][col] for col in cols]) == 1 # sum(x(i,j),j=1,4)=1, i=1,4for col in cols:AssignLP += pulp.lpSum([x[row][col] for row in rows]) == 1 # sum(x(i,j),i=1,4)=1, j=1,4快捷方法對于約束條件的定義與對目標函數的定義相似,使用字典定義參數,使用循環定義約束條件,使程序簡單、結構清楚。
(5)求解和結果輸出
AssignLP.solve() # youcansprint(AssignLP.name)member = ["隊員A","隊員B","隊員C","隊員D"]style = ["自由泳","蛙泳","蝶泳","仰泳"]if pulp.LpStatus[AssignLP.status] == "Optimal": # 獲得最優解xValue = [v.varValue for v in AssignLP.variables()]# [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]xOpt = np.array(xValue).reshape((4, 4)) # 將 xValue 格式轉換為 4x4 矩陣print("最佳分配:" )for row in rows:print("{}\t{} 參加項目:{}".format(xOpt[row],member[row],style[np.argmax(xOpt[row])]))print("預測最好成績為:{}".format(pulp.value(AssignLP.objective)))xValue 獲得的是列表變量,通過 numpy 的 reshape() 函數轉換為 4*4 矩陣,便于格式化輸出。
3.4 指派問題 Python 例程
# mathmodel08_v1.py # Demo08 of mathematical modeling algorithm # Solving assignment problem with PuLP. # Copyright 2021 Youcans, XUPT # Crated:2021-06-02 # Python小白的數學建模課 @ Youcansimport pulp # 導入 pulp 庫 import numpy as np# 主程序 def main():# 問題建模:"""決策變量:x(i,j) = 0, 第 i 個人不游第 j 種姿勢x(i,j) = 1, 第 i 個人游第 j 種姿勢i=1,4, j=1,4目標函數:min time = sum(sum(c(i,j)*x(i,j))), i=1,4, j=1,4約束條件:sum(x(i,j),j=1,4)=1, i=1,4sum(x(i,j),i=1,4)=1, j=1,4變量取值范圍:x(i,j) = 0,1 """# 游泳比賽的指派問題 (assignment problem)# 1.建立優化問題 AssignLP: 求最小值(LpMinimize)AssignLP = pulp.LpProblem("Assignment_problem_for_swimming_relay_race", sense=pulp.LpMinimize) # 定義問題,求最小值# 2. 建立變量rows = cols = range(0, 4)x = pulp.LpVariable.dicts("x", (rows, cols), cat="Binary")# 3. 設置目標函數scoreM = [[56,74,61,63],[63,69,65,71],[57,77,63,67],[55,76,62,62]]AssignLP += pulp.lpSum([[x[row][col]*scoreM[row][col] for row in rows] for col in cols])# 4. 施加約束for row in rows:AssignLP += pulp.lpSum([x[row][col] for col in cols]) == 1 # sum(x(i,j),j=1,4)=1, i=1,4for col in cols:AssignLP += pulp.lpSum([x[row][col] for row in rows]) == 1 # sum(x(i,j),i=1,4)=1, j=1,4# 5. 求解AssignLP.solve() # youcans# 6. 打印結果print(AssignLP.name)member = ["隊員A","隊員B","隊員C","隊員D"]style = ["自由泳","蛙泳","蝶泳","仰泳"]if pulp.LpStatus[AssignLP.status] == "Optimal": # 獲得最優解xValue = [v.varValue for v in AssignLP.variables()]# [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]xOpt = np.array(xValue).reshape((4, 4)) # 將 xValue 格式轉換為 4x4 矩陣print("最佳分配:" )for row in rows:print("{}\t{} 參加項目:{}".format(xOpt[row],member[row],style[np.argmax(xOpt[row])]))print("預測最好成績為:{}".format(pulp.value(AssignLP.objective)))returnif __name__ == '__main__': # Copyright 2021 YouCans, XUPTmain() # Python小白的數學建模課 @ Youcans3.5 Python 例程運行結果
Welcome to the CBC MILP Solver Version: 2.9.0 Build Date: Feb 12 2015 Result - Optimal solution foundAssignment_problem_for_swimming_relay_race 最佳分配: [0. 0. 1. 0.] 隊員A 參加項目:蝶泳 [0. 1. 0. 0.] 隊員B 參加項目:蛙泳 [1. 0. 0. 0.] 隊員C 參加項目:自由泳 [0. 0. 0. 1.] 隊員D 參加項目:仰泳 預測最好成績為:249.04. 案例 2:PuLP求解選址問題
4.1 消防站的選址問題
例題 2:某城市有 8 個區,每個區最多建一個消防站,擬建設消防站到各區的最長時間如下表所示。現要求任何區域發生火警時,消防車能在 10分鐘內趕到。在此條件下盡量減少消防站數量,應該在哪幾個區建設消防站?
| 1 | 7 | 12 | 18 | 20 | 24 | 26 | 25 | 28 |
| 2 | 14 | 5 | 8 | 15 | 16 | 18 | 18 | 18 |
| 3 | 19 | 9 | 4 | 14 | 10 | 22 | 16 | 13 |
| 4 | 14 | 15 | 15 | 10 | 18 | 15 | 14 | 18 |
| 5 | 20 | 18 | 12 | 20 | 9 | 25 | 14 | 12 |
| 6 | 18 | 21 | 20 | 16 | 20 | 6 | 10 | 15 |
| 7 | 22 | 18 | 20 | 15 | 16 | 15 | 5 | 9 |
| 8 | 30 | 22 | 15 | 20 | 14 | 18 | 8 | 6 |
4.2 選址問題建模分析
首先判斷這是一個集合覆蓋問題,要求從 8 個候選消防站中選擇若干個,在所有需求點得到服務的時間都小于臨界值 10分鐘的條件下,選擇消防站的數量最少。本問題不考慮各候選站點建設費用的差異,即不帶權重。
定義參數 RijR_{ij}Rij? 為每個消防站的覆蓋范圍:
Rij={1,消防站j可以覆蓋區域i0,消防站j不能覆蓋區域iR_{ij} = \begin{cases} 1,& 消防站\ j\ 可以覆蓋區域\ i\\ 0,& 消防站\ j\ 不能覆蓋區域\ i \end{cases} Rij?={1,0,?消防站?j?可以覆蓋區域?i消防站?j?不能覆蓋區域?i?
由擬建消防站到各區的最長時間表可以得到參數 RijR_{ij}Rij? 如下表:
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| 5 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
| 6 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
| 7 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 8 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
定義決策變量 xjx_jxj? 為選中的服務站:
xj={1,消防站j被選中0,消防站j未被選中x_j = \begin{cases} 1,& 消防站\ j\ 被選中\\ 0,& 消防站\ j\ 未被選中\end{cases} xj?={1,0,?消防站?j?被選中消防站?j?未被選中?
可以建立數學模型如下:
minf(x)=∑j=18xjs.t.:{∑j=18xjRij≥1,i=1,..8xj∈{0,1},j=1,..8min\; f(x) = \sum_{j=1}^8 x_{j}\\ s.t.:\;\begin{cases} \sum_{j=1}^8 x_j R_{ij} \geq 1, &i=1,..8\\ x_{j} \in \{0,1\}, &j=1,..8 \end{cases} minf(x)=j=1∑8?xj?s.t.:{∑j=18?xj?Rij?≥1,xj?∈{0,1},?i=1,..8j=1,..8?
選址問題的模型求解,用標準模型的優化算法對模型求解,得到優化結果。
模型求解的編程步驟與指派問題是一致的,且在例程中給出了詳細的注釋,就不再進行逐項解釋了。
需要注意的是,選址問題的決策變量、參數、約束條件的數量較大(N*M),如果對變量、約束條件逐個進行定義,編程過程將是非常冗長和痛苦的,因此需要使用列表、字典等快捷方式進行定義。對于更大規模的問題,模型中的數據要通過讀取數據文件獲得,就更需要采用這種方式來編程。
4.3 選址問題 Python 例程
# mathmodel09_v1.py # Demo08 of mathematical modeling algorithm # Solving set covering problem with PuLP. # Copyright 2021 Youcans, XUPT # Crated:2021-06-06 # Python小白的數學建模課 @ Youcansimport pulp # 導入 pulp 庫# 主程序 def main():# 問題建模:"""決策變量:x(j) = 0, 不選擇第 j 個消防站x(j) = 1, 選擇第 j 個消防站, j=1,8目標函數:min fx = sum(x(j)), j=1,8約束條件:sum(x(j)*R(i,j),j=1,8) >=1, i=1,8變量取值范圍:x(j) = 0,1"""# 消防站的選址問題 (set covering problem, site selection of fire station)# 1.建立優化問題 SetCoverLP: 求最小值(LpMinimize)SetCoverLP = pulp.LpProblem("SetCover_problem_for_fire_station", sense=pulp.LpMinimize) # 定義問題,求最小值# 2. 建立變量zones = list(range(8)) # 定義各區域 youcansx = pulp.LpVariable.dicts("zone", zones, cat="Binary") # 定義 0/1 變量,是否在該區域設消防站# 3. 設置目標函數SetCoverLP += pulp.lpSum([x[j] for j in range(8)]) # 設置消防站的個數# 4. 施加約束reachable = [[1, 0, 0, 0, 0, 0, 0, 0],[0, 1, 1, 0, 0, 0, 0, 0],[0, 1, 1, 0, 1, 0, 0, 0],[0, 0, 0, 1, 0, 0, 0, 0],[0, 0, 0, 0, 1, 0, 0, 0],[0, 0, 0, 0, 0, 1, 1, 0],[0, 0, 0, 0, 0, 0, 1, 1],[0, 0, 0, 0, 0, 0, 1, 1]] # 參數矩陣,第 i 消防站能否在 10分鐘內到達第 j 區域for i in range(8):SetCoverLP += pulp.lpSum([x[j]*reachable[j][i] for j in range(8)]) >= 1# 5. 求解SetCoverLP.solve()# 6. 打印結果print(SetCoverLP.name)temple = "區域 %(zone)d 的決策是:%(status)s" # 格式化輸出if pulp.LpStatus[SetCoverLP.status] == "Optimal": # 獲得最優解for i in range(8):output = {'zone': i+1, # 與問題中區域 1~8 一致'status': '建站' if x[i].varValue else '--'}print(temple % output)print("需要建立 {} 個消防站。".format(pulp.value(SetCoverLP.objective)))returnif __name__ == '__main__': # Copyright 2021 YouCans, XUPTmain() # Python小白的數學建模課 @ Youcans4.4 Python 例程運行結果
Welcome to the CBC MILP Solver Version: 2.9.0 Build Date: Feb 12 2015 Result - Optimal solution foundSetCover_problem_for_fire_station 區域 1 的決策是:建站 區域 2 的決策是:-- 區域 3 的決策是:建站 區域 4 的決策是:建站 區域 5 的決策是:-- 區域 6 的決策是:建站 區域 7 的決策是:建站 區域 8 的決策是:-- 需要建立 5.0 個消防站5. 小結
【本節完】
版權聲明:
歡迎關注『Python小白的數學建模課 @ Youcans』 原創作品
原創作品,轉載必須標注原文鏈接:(https://blog.csdn.net/youcans/article/details/117650843)。
Copyright 2021 Youcans, XUPT
Crated:2021-06-06
歡迎關注 『Python小白的數學建模課 @ Youcans』 系列,持續更新
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.數據導入
Python小白的數學建模課-03.線性規劃
Python小白的數學建模課-04.整數規劃
Python小白的數學建模課-05.0-1規劃
Python小白的數學建模課-06.固定費用問題
Python小白的數學建模課-07.選址問題
Python小白的數學建模課-09.微分方程模型
Python小白的數學建模課-10.微分方程邊值問題
Python小白的數學建模課-12.非線性規劃
Python小白的數學建模課-15.圖論的基本概念
Python小白的數學建模課-16.最短路徑算法
Python小白的數學建模課-17.條件最短路徑算法
Python小白的數學建模課-18.最小生成樹問題
Python小白的數學建模課-19.網絡流優化問題
Python小白的數學建模課-20.網絡流優化案例
Python小白的數學建模課-21.關鍵路徑法
Python小白的數學建模課-22.插值方法
Python小白的數學建模課-23.數據擬合全集
Python小白的數學建模課-A1.國賽賽題類型分析
Python小白的數學建模課-A2.2021年數維杯C題探討
Python小白的數學建模課-A3.12個新冠疫情數模競賽賽題及短評
Python小白的數學建模課-B2. 新冠疫情 SI模型
Python小白的數學建模課-B3. 新冠疫情 SIS模型
Python小白的數學建模課-B4. 新冠疫情 SIR模型
Python小白的數學建模課-B5. 新冠疫情 SEIR模型
Python小白的數學建模課-B6. 新冠疫情 SEIR改進模型
Python數模筆記-PuLP庫
Python數模筆記-StatsModels統計回歸
Python數模筆記-Sklearn
Python數模筆記-NetworkX
Python數模筆記-模擬退火算法
總結
以上是生活随笔為你收集整理的Python小白的数学建模课-07.选址问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenCV 例程200篇】71. 连
- 下一篇: Python数模笔记-模拟退火算法(3)