動態(tài)規(guī)劃的三要素:最優(yōu)子結(jié)構(gòu),邊界和狀態(tài)轉(zhuǎn)移函數(shù),最優(yōu)子結(jié)構(gòu)是指每個階段的最優(yōu)狀態(tài)可以從之前某個階段的某個或某些狀態(tài)直接得到(子問題的最優(yōu)解能夠決定這個問題的最優(yōu)解),邊界指的是問題最小子集的解(初始范圍),狀態(tài)轉(zhuǎn)移函數(shù)是指從一個階段向另一個階段過度的具體形式,描述的是兩個相鄰子問題之間的關(guān)系(遞推式)
創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)東昌府,10年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
重疊子問題,對每個子問題只計算一次,然后將其計算的結(jié)果保存到一個表格中,每一次需要上一個子問題解時,進行調(diào)用,只要o(1)時間復(fù)雜度,準(zhǔn)確的說,動態(tài)規(guī)劃是利用空間去換取時間的算法.
判斷是否可以利用動態(tài)規(guī)劃求解,第一個是判斷是否存在重疊子問題。
爬樓梯
假設(shè)你正在爬樓梯。需要 n 階你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數(shù)。
示例 1:
輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1. ?1 階 + 1 階
2. ?2 階
示例 2:
輸入: 3
輸出: 3
解釋: 有三種方法可以爬到樓頂。
1. ?1 階 + 1 階 + 1 階
2. ?1 階 + 2 階
3. ?2 階 + 1 階
分析:
假定n=10,首先考慮最后一步的情況,要么從第九級臺階再走一級到第十級,要么從第八級臺階走兩級到第十級,因而,要想到達第十級臺階,最后一步一定是從第八級或者第九級臺階開始.也就是說已知從地面到第八級臺階一共有X種走法,從地面到第九級臺階一共有Y種走法,那么從地面到第十級臺階一共有X+Y種走法.
即F(10)=F(9)+F(8)
分析到這里,動態(tài)規(guī)劃的三要素出來了.
邊界:F(1)=1,F(2)=2
最優(yōu)子結(jié)構(gòu):F(10)的最優(yōu)子結(jié)構(gòu)即F(9)和F(8)
狀態(tài)轉(zhuǎn)移函數(shù):F(n)=F(n-1)+F(n-2)
class Solution(object):
def climbStairs(self, n):
? ? """
? ? :type n: int
? ? :rtype: int
? ? """
? ? if n=2:
? ? ? ? return n
? ? a=1#邊界
? ? b=2#邊界
? ? temp=0
? ? for i in range(3,n+1):
? ? ? ? temp=a+b#狀態(tài)轉(zhuǎn)移
? ? ? ? a=b#最優(yōu)子結(jié)構(gòu)
? ? ? ? b=temp#最優(yōu)子結(jié)構(gòu)
? ? return temp
利用動態(tài)規(guī)劃的思想計算編輯距離。
編輯距離是指兩個字串之間,由一個轉(zhuǎn)成另一個所需的最少編輯操作次數(shù)。通常來說,編輯距離越小,兩個文本的相似性越大。這里的編輯操作主要包括三種:
插入:將一個字符插入某個字符串;
刪除:將字符串中的某個字符刪除;
替換:將字符串中的某個字符替換為另外一個字符。
那么,如何用Python計算編輯距離呢?我們可以從較為簡單的情況進行分析。
當(dāng)兩個字符串都為空串,那么編輯距離為0;
當(dāng)其中一個字符串為空串時,那么編輯距離為另一個非空字符串的長度;
當(dāng)兩個字符串均為非空時(長度分別為 i 和 j ),取以下三種情況最小值即可:
1、長度分別為 i-1 和 j 的字符串的編輯距離已知,那么加1即可;
2、長度分別為 i 和 j-1 的字符串的編輯距離已知,那么加1即可;
3、長度分別為 i-1 和 j-1 的字符串的編輯距離已知,此時考慮兩種情況,若第i個字符和第j個字符不同,那么加1即可;如果相同,那么不需要加1。
很明顯,上述算法的思想即為 動態(tài)規(guī)劃 。
求長度為m和n的字符串的編輯距離,首先定義函數(shù)——edit(i, j),它表示第一個長度為i的字符串與第二個長度為j的字符串之間的編輯距離。動態(tài)規(guī)劃表達式可以寫為:
if i == 0 且 j == 0,edit(i, j) = 0
if (i == 0 且 j 0 )或者 (i 0 且j == 0),edit(i, j) = i + j
if i ≥ 1 且 j ≥ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + d(i, j) },當(dāng)?shù)谝粋€字符串的第i個字符不等于第二個字符串的第j個字符時,d(i, j) = 1;否則,d(i, j) = 0。
def edit_distance(word1, word2):
len1 = len(word1)
len2 = len(word2)
dp = np.zeros((len1 + 1,len2 + 1))
for i in range(len1 + 1):
? ? dp[i][0] = i? ?
for j in range(len2 + 1):
? ? dp[0][j] = j
for i in range(1, len1 + 1):
? ? for j in range(1, len2 + 1):
? ? ? ? delta = 0 if word1[i-1] == word2[j-1] else 1
? ? ? ? dp[i][j] = min(dp[i - 1][j - 1] + delta, min(dp[i-1][j] + 1, dp[i][j - 1] + 1))
return dp[len1][len2]
edit_distance('牛奶','華西奶')
結(jié)果:2
想象一下,您有一個線性方程組和不等式系統(tǒng)。這樣的系統(tǒng)通常有許多可能的解決方案。線性規(guī)劃是一組數(shù)學(xué)和計算工具,可讓您找到該系統(tǒng)的特定解,該解對應(yīng)于某些其他線性函數(shù)的最大值或最小值。
混合整數(shù)線性規(guī)劃是 線性規(guī)劃 的擴展。它處理至少一個變量采用離散整數(shù)而不是連續(xù)值的問題。盡管乍一看混合整數(shù)問題與連續(xù)變量問題相似,但它們在靈活性和精度方面具有顯著優(yōu)勢。
整數(shù)變量對于正確表示自然用整數(shù)表示的數(shù)量很重要,例如生產(chǎn)的飛機數(shù)量或服務(wù)的客戶數(shù)量。
一種特別重要的整數(shù)變量是 二進制變量 。它只能取 零 或 一 的值,在做出是或否的決定時很有用,例如是否應(yīng)該建造工廠或者是否應(yīng)該打開或關(guān)閉機器。您還可以使用它們來模擬邏輯約束。
線性規(guī)劃是一種基本的優(yōu)化技術(shù),已在科學(xué)和數(shù)學(xué)密集型領(lǐng)域使用了數(shù)十年。它精確、相對快速,適用于一系列實際應(yīng)用。
混合整數(shù)線性規(guī)劃允許您克服線性規(guī)劃的許多限制。您可以使用分段線性函數(shù)近似非線性函數(shù)、使用半連續(xù)變量、模型邏輯約束等。它是一種計算密集型工具,但計算機硬件和軟件的進步使其每天都更加適用。
通常,當(dāng)人們試圖制定和解決優(yōu)化問題時,第一個問題是他們是否可以應(yīng)用線性規(guī)劃或混合整數(shù)線性規(guī)劃。
以下文章說明了線性規(guī)劃和混合整數(shù)線性規(guī)劃的一些用例:
隨著計算機能力的增強、算法的改進以及更多用戶友好的軟件解決方案的出現(xiàn),線性規(guī)劃,尤其是混合整數(shù)線性規(guī)劃的重要性隨著時間的推移而增加。
解決線性規(guī)劃問題的基本方法稱為,它有多種變體。另一種流行的方法是。
混合整數(shù)線性規(guī)劃問題可以通過更復(fù)雜且計算量更大的方法來解決,例如,它在幕后使用線性規(guī)劃。這種方法的一些變體是,它涉及使用 切割平面 ,以及。
有幾種適用于線性規(guī)劃和混合整數(shù)線性規(guī)劃的合適且眾所周知的 Python 工具。其中一些是開源的,而另一些是專有的。您是否需要免費或付費工具取決于問題的規(guī)模和復(fù)雜性,以及對速度和靈活性的需求。
值得一提的是,幾乎所有廣泛使用的線性規(guī)劃和混合整數(shù)線性規(guī)劃庫都是以 Fortran 或 C 或 C++ 原生和編寫的。這是因為線性規(guī)劃需要對(通常很大)矩陣進行計算密集型工作。此類庫稱為求解器。Python 工具只是求解器的包裝器。
Python 適合圍繞本機庫構(gòu)建包裝器,因為它可以很好地與 C/C++ 配合使用。對于本教程,您不需要任何 C/C++(或 Fortran),但如果您想了解有關(guān)此酷功能的更多信息,請查看以下資源:
基本上,當(dāng)您定義和求解模型時,您使用 Python 函數(shù)或方法調(diào)用低級庫,該庫執(zhí)行實際優(yōu)化工作并將解決方案返回給您的 Python 對象。
幾個免費的 Python 庫專門用于與線性或混合整數(shù)線性規(guī)劃求解器交互:
在本教程中,您將使用SciPy和PuLP來定義和解決線性規(guī)劃問題。
在本節(jié)中,您將看到線性規(guī)劃問題的兩個示例:
您將在下一節(jié)中使用 Python 來解決這兩個問題。
考慮以下線性規(guī)劃問題:
你需要找到X和?使得紅色,藍色和黃色的不平等,以及不平等X 0和? 0,是滿意的。同時,您的解決方案必須對應(yīng)于z的最大可能值。
您需要找到的自變量(在本例中為 x 和 y )稱為 決策變量 。要最大化或最小化的決策變量的函數(shù)(在本例中為 z) 稱為 目標(biāo)函數(shù) 、 成本函數(shù) 或僅稱為 目標(biāo) 。您需要滿足的 不等式 稱為 不等式約束 。您還可以在稱為 等式約束 的約束中使用方程。
這是您如何可視化問題的方法:
紅線代表的功能2 X + Y = 20,和它上面的紅色區(qū)域示出了紅色不等式不滿足。同樣,藍線是函數(shù) 4 x + 5 y = 10,藍色區(qū)域被禁止,因為它違反了藍色不等式。黃線是 x + 2 y = 2,其下方的黃色區(qū)域是黃色不等式無效的地方。
如果您忽略紅色、藍色和黃色區(qū)域,則僅保留灰色區(qū)域。灰色區(qū)域的每個點都滿足所有約束,是問題的潛在解決方案。該區(qū)域稱為 可行域 ,其點為 可行解 。在這種情況下,有無數(shù)可行的解決方案。
您想最大化z。對應(yīng)于最大z的可行解是 最優(yōu)解 。如果您嘗試最小化目標(biāo)函數(shù),那么最佳解決方案將對應(yīng)于其可行的最小值。
請注意,z是線性的。你可以把它想象成一個三維空間中的平面。這就是為什么最優(yōu)解必須在可行區(qū)域的 頂點 或角上的原因。在這種情況下,最佳解決方案是紅線和藍線相交的點,稍后您將看到。
有時,可行區(qū)域的整個邊緣,甚至整個區(qū)域,都可以對應(yīng)相同的z值。在這種情況下,您有許多最佳解決方案。
您現(xiàn)在已準(zhǔn)備好使用綠色顯示的附加等式約束來擴展問題:
方程式 x + 5 y = 15,以綠色書寫,是新的。這是一個等式約束。您可以通過向上一張圖像添加相應(yīng)的綠線來將其可視化:
現(xiàn)在的解決方案必須滿足綠色等式,因此可行區(qū)域不再是整個灰色區(qū)域。它是綠線從與藍線的交點到與紅線的交點穿過灰色區(qū)域的部分。后一點是解決方案。
如果插入x的所有值都必須是整數(shù)的要求,那么就會得到一個混合整數(shù)線性規(guī)劃問題,可行解的集合又會發(fā)生變化:
您不再有綠線,只有沿線的x值為整數(shù)的點??尚薪馐腔疑尘吧系木G點,此時最優(yōu)解離紅線最近。
這三個例子說明了 可行的線性規(guī)劃問題 ,因為它們具有有界可行區(qū)域和有限解。
如果沒有解,線性規(guī)劃問題是 不可行的 。當(dāng)沒有解決方案可以同時滿足所有約束時,通常會發(fā)生這種情況。
例如,考慮如果添加約束x + y 1會發(fā)生什么。那么至少有一個決策變量(x或y)必須是負(fù)數(shù)。這與給定的約束x 0 和y 0相沖突。這樣的系統(tǒng)沒有可行的解決方案,因此稱為不可行的。
另一個示例是添加與綠線平行的第二個等式約束。這兩行沒有共同點,因此不會有滿足這兩個約束的解決方案。
一個線性規(guī)劃問題是 無界的 ,如果它的可行區(qū)域是無界,將溶液不是有限。這意味著您的變量中至少有一個不受約束,可以達到正無窮大或負(fù)無窮大,從而使目標(biāo)也無限大。
例如,假設(shè)您采用上面的初始問題并刪除紅色和黃色約束。從問題中刪除約束稱為 放松 問題。在這種情況下,x和y不會在正側(cè)有界。您可以將它們增加到正無窮大,從而產(chǎn)生無限大的z值。
在前面的部分中,您研究了一個與任何實際應(yīng)用程序無關(guān)的抽象線性規(guī)劃問題。在本小節(jié)中,您將找到與制造業(yè)資源分配相關(guān)的更具體和實用的優(yōu)化問題。
假設(shè)一家工廠生產(chǎn)四種不同的產(chǎn)品,第一種產(chǎn)品的日產(chǎn)量為x ?,第二種產(chǎn)品的產(chǎn)量為x 2,依此類推。目標(biāo)是確定每種產(chǎn)品的利潤最大化日產(chǎn)量,同時牢記以下條件:
數(shù)學(xué)模型可以這樣定義:
目標(biāo)函數(shù)(利潤)在條件 1 中定義。人力約束遵循條件 2。對原材料 A 和 B 的約束可以從條件 3 和條件 4 中通過對每種產(chǎn)品的原材料需求求和得出。
最后,產(chǎn)品數(shù)量不能為負(fù),因此所有決策變量必須大于或等于零。
與前面的示例不同,您無法方便地將其可視化,因為它有四個決策變量。但是,無論問題的維度如何,原理都是相同的。
在本教程中,您將使用兩個Python 包來解決上述線性規(guī)劃問題:
SciPy 設(shè)置起來很簡單。安裝后,您將擁有開始所需的一切。它的子包 scipy.optimize 可用于線性和非線性優(yōu)化。
PuLP 允許您選擇求解器并以更自然的方式表述問題。PuLP 使用的默認(rèn)求解器是COIN-OR Branch and Cut Solver (CBC)。它連接到用于線性松弛的COIN-OR 線性規(guī)劃求解器 (CLP)和用于切割生成的COIN-OR 切割生成器庫 (CGL)。
另一個偉大的開源求解器是GNU 線性規(guī)劃工具包 (GLPK)。一些著名且非常強大的商業(yè)和專有解決方案是Gurobi、CPLEX和XPRESS。
除了在定義問題時提供靈活性和運行各種求解器的能力外,PuLP 使用起來不如 Pyomo 或 CVXOPT 等替代方案復(fù)雜,后者需要更多的時間和精力來掌握。
要學(xué)習(xí)本教程,您需要安裝 SciPy 和 PuLP。下面的示例使用 SciPy 1.4.1 版和 PuLP 2.1 版。
您可以使用pip以下方法安裝兩者:
您可能需要運行pulptest或sudo pulptest啟用 PuLP 的默認(rèn)求解器,尤其是在您使用 Linux 或 Mac 時:
或者,您可以下載、安裝和使用 GLPK。它是免費和開源的,適用于 Windows、MacOS 和 Linux。在本教程的后面部分,您將看到如何將 GLPK(除了 CBC)與 PuLP 一起使用。
在 Windows 上,您可以下載檔案并運行安裝文件。
在 MacOS 上,您可以使用 Homebrew:
在 Debian 和 Ubuntu 上,使用apt來安裝glpk和glpk-utils:
在Fedora,使用dnf具有g(shù)lpk-utils:
您可能還會發(fā)現(xiàn)conda對安裝 GLPK 很有用:
安裝完成后,可以查看GLPK的版本:
有關(guān)詳細(xì)信息,請參閱 GLPK 關(guān)于使用Windows 可執(zhí)行文件和Linux 軟件包進行安裝的教程。
在本節(jié)中,您將學(xué)習(xí)如何使用 SciPy優(yōu)化和求根庫進行線性規(guī)劃。
要使用 SciPy 定義和解決優(yōu)化問題,您需要導(dǎo)入scipy.optimize.linprog():
現(xiàn)在您已經(jīng)linprog()導(dǎo)入,您可以開始優(yōu)化。
讓我們首先解決上面的線性規(guī)劃問題:
linprog()僅解決最小化(而非最大化)問題,并且不允許具有大于或等于符號 ( ) 的不等式約束。要解決這些問題,您需要在開始優(yōu)化之前修改您的問題:
引入這些更改后,您將獲得一個新系統(tǒng):
該系統(tǒng)與原始系統(tǒng)等效,并且將具有相同的解決方案。應(yīng)用這些更改的唯一原因是克服 SciPy 與問題表述相關(guān)的局限性。
下一步是定義輸入值:
您將上述系統(tǒng)中的值放入適當(dāng)?shù)牧斜怼⒃M或NumPy 數(shù)組中:
注意:請注意行和列的順序!
約束左側(cè)和右側(cè)的行順序必須相同。每一行代表一個約束。
來自目標(biāo)函數(shù)和約束左側(cè)的系數(shù)的順序必須匹配。每列對應(yīng)一個決策變量。
下一步是以與系數(shù)相同的順序定義每個變量的界限。在這種情況下,它們都在零和正無窮大之間:
此語句是多余的,因為linprog()默認(rèn)情況下采用這些邊界(零到正無窮大)。
注:相反的float("inf"),你可以使用math.inf,numpy.inf或scipy.inf。
最后,是時候優(yōu)化和解決您感興趣的問題了。你可以這樣做linprog():
參數(shù)c是指來自目標(biāo)函數(shù)的系數(shù)。A_ub和b_ub分別與不等式約束左邊和右邊的系數(shù)有關(guān)。同樣,A_eq并b_eq參考等式約束。您可以使用bounds提供決策變量的下限和上限。
您可以使用該參數(shù)method來定義要使用的線性規(guī)劃方法。有以下三種選擇:
linprog() 返回具有以下屬性的數(shù)據(jù)結(jié)構(gòu):
您可以分別訪問這些值:
這就是您獲得優(yōu)化結(jié)果的方式。您還可以以圖形方式顯示它們:
如前所述,線性規(guī)劃問題的最優(yōu)解位于可行區(qū)域的頂點。在這種情況下,可行區(qū)域只是藍線和紅線之間的綠線部分。最優(yōu)解是代表綠線和紅線交點的綠色方塊。
如果要排除相等(綠色)約束,只需刪除參數(shù)A_eq并b_eq從linprog()調(diào)用中刪除:
解決方案與前一種情況不同。你可以在圖表上看到:
在這個例子中,最優(yōu)解是紅色和藍色約束相交的可行(灰色)區(qū)域的紫色頂點。其他頂點,如黃色頂點,具有更高的目標(biāo)函數(shù)值。
您可以使用 SciPy 來解決前面部分所述的資源分配問題:
和前面的例子一樣,你需要從上面的問題中提取必要的向量和矩陣,將它們作為參數(shù)傳遞給.linprog(),然后得到結(jié)果:
結(jié)果告訴您最大利潤是1900并且對應(yīng)于x ? = 5 和x ? = 45。在給定條件下生產(chǎn)第二和第四個產(chǎn)品是沒有利潤的。您可以在這里得出幾個有趣的結(jié)論:
opt.statusis0和opt.successis True,說明優(yōu)化問題成功求解,最優(yōu)可行解。
SciPy 的線性規(guī)劃功能主要用于較小的問題。對于更大和更復(fù)雜的問題,您可能會發(fā)現(xiàn)其他庫更適合,原因如下:
幸運的是,Python 生態(tài)系統(tǒng)為線性編程提供了幾種替代解決方案,這些解決方案對于更大的問題非常有用。其中之一是 PuLP,您將在下一節(jié)中看到它的實際應(yīng)用。
PuLP 具有比 SciPy 更方便的線性編程 API。您不必在數(shù)學(xué)上修改您的問題或使用向量和矩陣。一切都更干凈,更不容易出錯。
像往常一樣,您首先導(dǎo)入您需要的內(nèi)容:
現(xiàn)在您已經(jīng)導(dǎo)入了 PuLP,您可以解決您的問題。
您現(xiàn)在將使用 PuLP 解決此系統(tǒng):
第一步是初始化一個實例LpProblem來表示你的模型:
您可以使用該sense參數(shù)來選擇是執(zhí)行最小化(LpMinimize或1,這是默認(rèn)值)還是最大化(LpMaximize或-1)。這個選擇會影響你的問題的結(jié)果。
一旦有了模型,就可以將決策變量定義為LpVariable類的實例:
您需要提供下限,lowBound=0因為默認(rèn)值為負(fù)無窮大。該參數(shù)upBound定義了上限,但您可以在此處省略它,因為它默認(rèn)為正無窮大。
可選參數(shù)cat定義決策變量的類別。如果您使用的是連續(xù)變量,則可以使用默認(rèn)值"Continuous"。
您可以使用變量x和y創(chuàng)建表示線性表達式和約束的其他 PuLP 對象:
當(dāng)您將決策變量與標(biāo)量相乘或構(gòu)建多個決策變量的線性組合時,您會得到一個pulp.LpAffineExpression代表線性表達式的實例。
注意:您可以增加或減少變量或表達式,你可以乘他們常數(shù),因為紙漿類實現(xiàn)一些Python的特殊方法,即模擬數(shù)字類型一樣__add__(),__sub__()和__mul__()。這些方法用于像定制運營商的行為+,-和*。
類似地,您可以將線性表達式、變量和標(biāo)量與運算符 ==、=以獲取表示模型線性約束的紙漿.LpConstraint實例。
注:也有可能與豐富的比較方法來構(gòu)建的約束.__eq__(),.__le__()以及.__ge__()定義了運營商的行為==,=。
考慮到這一點,下一步是創(chuàng)建約束和目標(biāo)函數(shù)并將它們分配給您的模型。您不需要創(chuàng)建列表或矩陣。只需編寫 Python 表達式并使用+=運算符將它們附加到模型中:
在上面的代碼中,您定義了包含約束及其名稱的元組。LpProblem允許您通過將約束指定為元組來向模型添加約束。第一個元素是一個LpConstraint實例。第二個元素是該約束的可讀名稱。
設(shè)置目標(biāo)函數(shù)非常相似:
或者,您可以使用更短的符號:
現(xiàn)在您已經(jīng)添加了目標(biāo)函數(shù)并定義了模型。
注意:您可以使用運算符將 約束或目標(biāo)附加到模型中,+=因為它的類LpProblem實現(xiàn)了特殊方法.__iadd__(),該方法用于指定 的行為+=。
對于較大的問題,lpSum()與列表或其他序列一起使用通常比重復(fù)+運算符更方便。例如,您可以使用以下語句將目標(biāo)函數(shù)添加到模型中:
它產(chǎn)生與前一條語句相同的結(jié)果。
您現(xiàn)在可以看到此模型的完整定義:
模型的字符串表示包含所有相關(guān)數(shù)據(jù):變量、約束、目標(biāo)及其名稱。
注意:字符串表示是通過定義特殊方法構(gòu)建的.__repr__()。有關(guān) 的更多詳細(xì)信息.__repr__(),請查看Pythonic OOP 字符串轉(zhuǎn)換:__repr__vs__str__ .
最后,您已準(zhǔn)備好解決問題。你可以通過調(diào)用.solve()你的模型對象來做到這一點。如果要使用默認(rèn)求解器 (CBC),則不需要傳遞任何參數(shù):
.solve()調(diào)用底層求解器,修改model對象,并返回解決方案的整數(shù)狀態(tài),1如果找到了最優(yōu)解。有關(guān)其余狀態(tài)代碼,請參閱LpStatus[]。
你可以得到優(yōu)化結(jié)果作為 的屬性model。該函數(shù)value()和相應(yīng)的方法.value()返回屬性的實際值:
model.objective持有目標(biāo)函數(shù)model.constraints的值,包含松弛變量的值,以及對象x和y具有決策變量的最優(yōu)值。model.variables()返回一個包含決策變量的列表:
如您所見,此列表包含使用 的構(gòu)造函數(shù)創(chuàng)建的確切對象LpVariable。
結(jié)果與您使用 SciPy 獲得的結(jié)果大致相同。
注意:注意這個方法.solve()——它會改變對象的狀態(tài),x并且y!
您可以通過調(diào)用查看使用了哪個求解器.solver:
輸出通知您求解器是 CBC。您沒有指定求解器,因此 PuLP 調(diào)用了默認(rèn)求解器。
如果要運行不同的求解器,則可以將其指定為 的參數(shù).solve()。例如,如果您想使用 GLPK 并且已經(jīng)安裝了它,那么您可以solver=GLPK(msg=False)在最后一行使用。請記住,您還需要導(dǎo)入它:
現(xiàn)在你已經(jīng)導(dǎo)入了 GLPK,你可以在里面使用它.solve():
該msg參數(shù)用于顯示來自求解器的信息。msg=False禁用顯示此信息。如果要包含信息,則只需省略msg或設(shè)置msg=True。
您的模型已定義并求解,因此您可以按照與前一種情況相同的方式檢查結(jié)果:
使用 GLPK 得到的結(jié)果與使用 SciPy 和 CBC 得到的結(jié)果幾乎相同。
一起來看看這次用的是哪個求解器:
正如您在上面用突出顯示的語句定義的那樣model.solve(solver=GLPK(msg=False)),求解器是 GLPK。
您還可以使用 PuLP 來解決混合整數(shù)線性規(guī)劃問題。要定義整數(shù)或二進制變量,只需傳遞cat="Integer"或cat="Binary"到LpVariable。其他一切都保持不變:
在本例中,您有一個整數(shù)變量并獲得與之前不同的結(jié)果:
Nowx是一個整數(shù),如模型中所指定。(從技術(shù)上講,它保存一個小數(shù)點后為零的浮點值。)這一事實改變了整個解決方案。讓我們在圖表上展示這一點:
如您所見,最佳解決方案是灰色背景上最右邊的綠點。這是兩者的最大價值的可行的解決方案x和y,給它的最大目標(biāo)函數(shù)值。
GLPK 也能夠解決此類問題。
現(xiàn)在你可以使用 PuLP 來解決上面的資源分配問題:
定義和解決問題的方法與前面的示例相同:
在這種情況下,您使用字典 x來存儲所有決策變量。這種方法很方便,因為字典可以將決策變量的名稱或索引存儲為鍵,將相應(yīng)的LpVariable對象存儲為值。列表或元組的LpVariable實例可以是有用的。
上面的代碼產(chǎn)生以下結(jié)果:
如您所見,該解決方案與使用 SciPy 獲得的解決方案一致。最有利可圖的解決方案是每天生產(chǎn)5.0第一件產(chǎn)品和45.0第三件產(chǎn)品。
讓我們把這個問題變得更復(fù)雜和有趣。假設(shè)由于機器問題,工廠無法同時生產(chǎn)第一種和第三種產(chǎn)品。在這種情況下,最有利可圖的解決方案是什么?
現(xiàn)在您有另一個邏輯約束:如果x ? 為正數(shù),則x ? 必須為零,反之亦然。這是二元決策變量非常有用的地方。您將使用兩個二元決策變量y ? 和y ?,它們將表示是否生成了第一個或第三個產(chǎn)品:
除了突出顯示的行之外,代碼與前面的示例非常相似。以下是差異:
這是解決方案:
事實證明,最佳方法是排除第一種產(chǎn)品而只生產(chǎn)第三種產(chǎn)品。
就像有許多資源可以幫助您學(xué)習(xí)線性規(guī)劃和混合整數(shù)線性規(guī)劃一樣,還有許多具有 Python 包裝器的求解器可用。這是部分列表:
其中一些庫,如 Gurobi,包括他們自己的 Python 包裝器。其他人使用外部包裝器。例如,您看到可以使用 PuLP 訪問 CBC 和 GLPK。
您現(xiàn)在知道什么是線性規(guī)劃以及如何使用 Python 解決線性規(guī)劃問題。您還了解到 Python 線性編程庫只是本機求解器的包裝器。當(dāng)求解器完成其工作時,包裝器返回解決方案狀態(tài)、決策變量值、松弛變量、目標(biāo)函數(shù)等。
==================================
將列表傳遞給函數(shù)后,函數(shù)就能直接訪問其內(nèi)容
假設(shè)有一個用戶列表,要問候其中的每位用戶
將列表傳遞給函數(shù)后,函數(shù)就可對其進行修改,在函數(shù)中對這個列表所做的任何修改都是永久性的
一家為用戶提交的設(shè)計制作3D打印模型的公司,需要打印的設(shè)計存儲在一個列表中,打印后轉(zhuǎn)移到另一個列表中。
有時候需要禁止函數(shù)修改列表,為解決這個問題,可想向函數(shù)傳遞列表的副本而不是元件;這樣函數(shù)所做的任何修改都只影響副本,不影響元件
有時候,預(yù)先布置的函數(shù)需要接受多少個實參,python允許函數(shù)從調(diào)用語句中手機任意數(shù)量的實參
一個制作披薩的寒素,它需要接受很多配料,但無法確定顧客要多少種配料,下面函數(shù)只有一個形參*toppings,不管調(diào)用語句提供了多少實參,這個形參都將他們統(tǒng)統(tǒng)收入囊中
如果要讓函數(shù)接受不同類型的實參,必須在函數(shù)定義中將接納任意數(shù)量實參的形參放在最后
python先匹配位置實參和關(guān)鍵字實參,再將余下的實參收集到最后一個形參中
如果前邊的函數(shù)還需要一個表示披薩尺寸的實參,必須將該形參放在*toppings的前面
有時候,需要接受任意數(shù)量的實參,但預(yù)先不知道傳遞給函數(shù)的會是射門楊的信息,再這種情況下,可將函數(shù)編寫成能夠接受任意數(shù)量的鍵-值對,調(diào)用語句提供了多少就接受多少
創(chuàng)建用戶簡介:你知道你將收到有關(guān)用戶的信息,但不確定會是什么樣的信息,在下面示例中,build_profile()接受名和姓,同時還接受任意數(shù)量的關(guān)鍵字實參