0050算法笔记——【线性规划】单纯形算法(未完全实现)
? ? ? ??題外話:王曉東的《算法設計與分析》看到現在,終于遇到自己琢磨不透的代碼了。這里粘出來,求大神指點迷津,將代碼補充完整~
? ? 1、線性規劃問題及其表示
? ? 線性規劃問題可表示為如下形式:
? ??變量滿足約束條件(8.2)-(8.5)式的一組值稱為線性規劃問題的一個可行解。
? ? 所有可行解構成的集合稱為線性規劃問題的可行區域。
? ? 使目標函數取得極值的可行解稱為最優解。
? ? 在最優解處目標函數的值稱為最優值。
? ? 有些情況下可能不存在最優解。
? ? 通常有兩種情況:
? ? (1)根本沒有可行解,即給定的約束條件之間是相互排斥的,可行區域為空集;
? ? (2)目標函數沒有極值,也就是說在n 維空間中的某個方向上,目標函數值可以無限增大,而仍滿足約束條件,此時目標函數值無界。
? ? 例:
? ? ?
? ? ?這個問題的解為 (x1,x2,x3,x4) = (0,3.5,4.5,1);最優值為16。?
? ? 2、線性規劃基本定理
? ? ?約束條件(8.2)-(8.5)中n個約束以等號滿足的可行解稱為線性規劃問題的基本可行解。
? ? 若n>m,則基本可行解中至少有n-m個分量為0,也就是說,基本可行解中最多有m個分量非零。
? ? 線性規劃基本定理:如果線性規劃問題有最優解,則必有一基本可行最優解。
? ? 上述定理的重要意義在于,它把一個最優化問題轉化為一個組合問題,即在(8.2) -(8.5)式的m+n個約束條件中,確定最優解應滿足其中哪n個約束條件的問題。
? ? 由此可知,只要對各種不同的組合進行測試,并比較每種情況下的目標函數值,直到找到最優解。
? ? Dantzig于1948年提出了線性規劃問題的單純形算法。
? ? 單純形算法的特點是:
? (1)只對約束條件的若干組合進行測試,測試的每一步都使目標函數的值增加;
? (2)一般經過不大于m或n次迭代就可求得最優解。 ? ??
? ??3、約束標準型線性規劃問題的單純形算法?
? ??當線性規劃問題中沒有不等式約束(8.2)和(8.4)式,而只有等式約束(8.3)和變量非負約束(8.5)時,稱該線性規劃問題具有標準形式。
? ? 先考察一類更特殊的標準形式線性規劃問題。這一類線性規劃問題中,每一個等式約束中,至少有一個變量的系數為正,且這個變量只在該約束中出現。
? ? 在每一約束方程中選擇一個這樣的變量,并以它作為變量求解該約束方程。這樣選出來的變量稱為左端變量或基本變量,其總數為m個。剩下的n-m個變量稱為右端變量或非基本變量。
? ? 這一類特殊的標準形式線性規劃問題稱為約束標準型線性規劃問題。
? ? 雖然約束標準型線性規劃問題非常特殊,但是對于理解線性規劃問題的單純形算法是非常重要的。
? ? 任意一個線性規劃問題可以轉換為約束標準型線性規劃問題。
? ? ?例:
? ? ??
? ? ??
? ? ?任何約束標準型線性規劃問題,只要將所有非基本變量都置為0,從約束方程式中解出滿足約束的基本變量的值,可求得一個基本可行解。
? ? ?單純形算法的基本思想就是從一個基本可行解出發,進行一系列的基本可行解的變換。
? ? ?每次變換將一個非基本變量與一個基本變量互調位置,且保持當前的線性規劃問題是一個與原問題完全等價的標準線性規劃問題。
? ? ?基本可行解x=(7,0,0,12,0,10)。
? ? ?單純形算法的第1步:選出使目標函數增加的非基本變量作為入基變量。
? ? 查看單純形表的第1行(也稱之為z行)中標有非基本變量的各列中的值。
? ? 選出使目標函數增加的非基本變量作為入基變量。
? ? z行中的正系數非基本變量都滿足要求。
? ? 在上面單純形表的z行中只有1列為正,即非基本變量相應的列,其值為3。
? ? 選取非基本變量x3作為入基變量。
? ? 單純形算法的第2步:選取離基變量。
? ? 在單純形表中考察由第1步選出的入基變量所相應的列。
? ? 在一個基本變量變為負值之前,入基變量可以增到多大。
? ? 如果入基變量所在的列與基本變量所在行交叉處的表元素為負數,那么該元素將不受任何限制,相應的基本變量只會越變越大。
? ? 如果入基變量所在列的所有元素都是負值,則目標函數無界,已經得到了問題的無界解。
? ? 如果選出的列中有一個或多個元素為正數,要弄清是哪個數限制了入基變量值的增加。
? ? 受限的增加量可以用入基變量所在列的元素(稱為主元素)來除主元素所在行的“常數列”(最左邊的列)中元素而得到。所得到數值越小說明受到限制越多。
? ? 應該選取受到限制最多的基本變量作為離基變量,才能保證將入基變量與離基變量互調位置后,仍滿足約束條件。
? ? 上例中,惟一的一個值為正的z行元素是3,它所在列中有2個正元素,即4和3。
? ? min{12/4,10/3}=4,應該選取x4為離基變量;
? ? 入基變量x3取值為3。
? ? 單純形算法的第3步:轉軸變換。
? ? 轉軸變換的目的是將入基變量與離基變量互調位置。
? ? 給入基變量一個增值,使之成為基本變量;
? ? 修改離基變量,讓入基變量所在列中,離基變量所在行的元素值減為零,而使之成為非基本變量。
? ? 解離基變量所相應的方程,將入基變量x3用離基變量x4表示為
? ? 再將其代入其他基本變量和所在的行中消去x3 ,
? ? ?
? ??代入目標函數得到
? ? 形成新單純形表
? ? ?
? ? ?單純形算法的第4步:轉回并重復第1步,進一步改進目標函數值。
? ? ?不斷重復上述過程,直到z行的所有非基本變量系數都變成負值為止。這表明目標函數不可能再增加了。
? ? ?在上面的單純形表中,惟一的值為正的z行元素是非基本變量x2相應的列,其值為1/2。
? ? ?因此,選取非基本變量x2作為入基變量。
? ? ?它所在列中有惟一的正元素5/2,即基本變量x1相應行的元素。
? ? ?因此,選取x1為離基變量。
? ? ?再經步驟3的轉軸變換得到新單純形表。
? ? ?新單純形表z行的所有非基本變量系數都變成負值,求解過程結束。
? ? 整個問題的解可以從最后一張單純形表的常數列中讀出。
? ? 目標函數的最大值為11;
? ? 最優解為:x*=(0,4,5,0,0,11)。
? ??
? ? ?單純形算法計算步驟如下:
? ? 步驟1:選入基變量。
? ? 如果所有cj?0,則當前基本可行解為最優解,計算結束。
? ? 否則取ce>0相應的非基本變量xe為入基變量。
? ? 步驟2:選離基變量。
? ? 對于步驟1選出的入基變量xe ,如果所有aie?0 ,則最優解無界,計算結束。
? ? 否則計算
? ? ?
? ? 選取基本變量xk為離基變量。
? ? 新的基本變量下標集為
? ? 新的非基本變量下標集為
? ? 步驟3:作轉軸變換。
? ? 新單純形表中各元素變換如下。
? ? ?
? ? 步驟4:轉步驟1。
? ??4、將一般問題轉化為約束標準型?? ?
? ? 有幾種巧妙的辦法可以將一般的線性規劃問題轉換為約束標準型線性規劃問題。
? ? 首先,需要把(8.2)或(8.4)形式的不等式約束轉換為等式約束。
? ? 具體做法是,引入松弛變量,利用松弛變量的非負性,將不等式轉化為等式。
? ? 松馳變量記為yi,共有m1+m3個。
? ? 在求解過程中,應當將松弛變量與原來變量同樣對待。求解結束后,拋棄松弛變量。
? ? 注意松弛變量前的符號由相應的原不等式的方向所確定。
? ??
? ??為了進一步構造標準型約束,還需要引入m個人工變量,記為zi。
? ? 至此,原問題已經變換為等價的約束標準型線性規劃問題。
? ? 對極小化線性規劃問題,只要將目標函數乘以-1即可化為等價的極大化線性規劃問題。
? ? ?
? ? ?5、一般線性規劃問題的2階段單純形算法?
? ? ?引入人工變量后的線性規劃問題與原問題并不等價,除非所有zi都是0 。
? ? 為了解決這個問題,在求解時必須分2個階段進行。
? ? 第一階段用一個輔助目標函數替代原來的目標函數。
? ? 這個線性規劃問題稱為原線性規劃問題所相應的輔助線性規劃問題。
? ? 對輔助線性規劃問題用單純形算法求解。
? ? 如果原線性規劃問題有可行解,則輔助線性規劃問題就有最優解,且其最優值為0,即所有zi都為0。
? ? 在輔助線性規劃問題最后的單純形表中,所有zi均為非基本變量。
? ? 劃掉所有zi相應的列,剩下的就是只含xi和yi的約束標準型線性規劃問題了。
? ? 單純形算法第一階段的任務就是構造一個初始基本可行解。
? ? 單純形算法第二階段的目標是求解由第一階段導出的問題。
? ? 此時要用原來的目標函數進行求解。
? ? 如果在輔助線性規劃問題最后的單純形表中, zi不全為0,則原線性規劃問題沒有可行解,從而原線性規劃問題無解。
? ? ?6、一般線性規劃問題的2階段單純形算法?
? ? ?用單純形算法解一般的線性規劃問題時,可能會遇到退化的情形,即在迭代計算的某一步中,常數列中的某個元素的值變成0,使得相應的基本變量取值為0。
? ? ?如果選取退化的基本變量為離基變量,則作轉軸變換前后的目標函數值不變。在這種情況下,算法不能保證目標函數值嚴格遞增,因此,可能出現無限循環。
? ? ?考察下面的由Beale在1955年提出的退化問題的例子。
? ? ?按照2階段單純形算法求解該問題將出現無限循環。
? ? ?
? ? ?Bland提出避免循環的一個簡單易行的方法。
? ? ?Bland提出在單純形算法迭代中,按照下面的2個簡單規則就可以避免循環。
? ? ?規則1:設,取xe為入基變量。
? ? ?規則2:設?
? ? ?取xk為離基變量。
? ? ?算法leave(col)已經按照規則2選取離基變量。
? ? ?選取入基變量的算法enter(objrow) 中只要加一個break語句即可。
? ? ?7、算法描述和實現
?
//線性規劃 單純性算法 #include "stdafx.h" #include <cmath> #include <iostream> #include<fstream> using namespace std;class LinearProgram {public:LinearProgram(char * filename);~LinearProgram();void solve();private:int enter(int objrow);int leave(int col);int simplex(int objrow);int phase1();int phase2();int compute();void swapbasic(int row,int col);void pivot(int row,int col);void stats();//這個方法是干什么的?void setbasic(int * basicp);void output();int m, //約束總數n, //變量數m1, //不等式約束數<=m2, //等式約束m3, //不等式約束數>=n1,n2, //n1 = n + m3,n2 = n1 + m1error, //記錄錯誤類型*basic, //基本變量下標*nonbasic; //非基本變量下標double **a,minmax; };//從標準輸入文件中讀入數據,構造初始單純形表 LinearProgram::LinearProgram(char *filename) {ifstream inFile;int i,j;double value;cout<<"按照下列格式輸入數據:"<<endl;cout<<"1:+1(max)或-1(min);m;n"<<endl;cout<<"2:m1;m2;m3"<<endl;cout<<"約束系數和右端項"<<endl;cout<<"目標函數系數"<<endl;error = 0;inFile.open(filename);inFile>>minmax;inFile>>m;inFile>>n;//輸入各類約束數inFile>>m1;inFile>>m2;inFile>>m3;if(m!=m1+m2+m3){error = 1;}n1 = n + m3;n2 = n + m1 + m3;Make2DArray(a,m+2,n1+1);//構造二維數組basic = new int[m+2];nonbasic = new int[n1+1];//初始化基本變量和非基本變量for(int i=0; i<=m+1; i++){for(int j=0; j<=n1; j++){a[i][j] = 0;}}for(int j=0; j<=n1; j++){nonbasic[j] = j;}//引入松弛變量和人工變量for(int i=1,j=n1+1; i<=m; i++,j++){basic[i] = j;}for(int i=m-m3+1,j=n+1; i<=m; i++,j++){a[i][j] = -1.0;a[m+1][j] = -1.0;}//輸入約束系數和右端項for(int i=1; i<=m; i++){for(int j=1; j<=n; j++){inFile>>value;a[i][j] = value;}inFile>>value;if(value<0) {error = 1;}a[i][0] = value;}//輸入目標函數系數for(int j=1; j<=n; j++){inFile>>value;a[0][j] = value * minmax;}//引入人工變量,構造第1階段的輔助目標函數for(int j=1; j<=n; j++){for(int i=m1+1,value=0.0; i<=m; i++){value += a[i][j];}a[m+1][j] = value;}inFile.close(); }//根據目標函數系數所在的行objrow,執行約束標準型線性規劃問題的單純形算法 int LinearProgram::simplex(int objrow) {for(int row = 0;;){int col = enter(objrow);if(col>0){row = leave(col);}else{return 0;}if(row>0){pivot(row,col);}else{return 2;}} }//根據目標函數系數所在行objrow,選取入基變量 int LinearProgram::enter(int objrow) {double temp = DBL_EPSILON; //?什么含義?for(int j=1,col=0; j<n1; j++){if(nonbasic[j]<=n2 && a[objrow][j]>temp){col = j;temp = a[objrow][j];break; //Bland避免循環法則}}return col; }//根據入基變量所在列col,選取離基變量 int LinearProgram::leave(int col) {double temp = DBL_MAX; //怎么定義的?值為多少?for(int i=1,row=0; i<=m; i++){double val = a[i][col];if(value>DBL_EPSLION){val = a[i][0]/val;if(val<temp){row = i;temp = val;}}}return row; }//以入基變量所在列col和離基變量所在行row交叉處元素a[row][col]為軸心,做轉軸變換 void LinearProgram::pivot(int row,int col) {for(int j=0; j<=n1; j++){if(j!=col){a[row][j] = a[row][j]/a[row][col];}}a[row][col] = 1.0/a[row][col];for(int i=0; i<m+1; i++){if(i!=row){for(int j=0; j<=n1; j++){if(j!=col){a[i][j] = a[i][j] - a[i][col]*a[row][j];if(fabs(a[i][j]<DBL_EPSLION){a[i][j] = 0.0;}}}}}swapbasic(row,col); }//交換基本變量row和非基本變量col的位置 void LinearProgram::swapbasic(int row,int col) {int temp = basic[row];basic[row] = nonbasic[col];nonbasic[col] = temp; }//對一般的線性規劃問題執行兩階段單純形算法 int LinearProgram::compute() {if(error>0){return error;}if(m!=m1){error = phase1();if(error>0){return error;}}rturn phase2(); }//構造初始基本可行解的第一階段單純形算法由phase1()實現 //輔助目標函數存儲在數組a的第trows行 int LinearProgram::phase1() {error = simplex(m+1);if(error>0){return error;}for(int i=1; i<=m; i++){if(basic[i]>n2){if(a[i][0]>DBL_EPSILON){return 3;}for(int j=1; j<=n1; j++){if(fabs(a[i][j]>=DBL_EPSILON){pivot(i,j);break;} }}}return 0; }//第二階段根據第一階段找到的基本可行解,對原來的目標函數用單純形算法求解 //原目標函數存儲在數組a的第0行 int LinearProgram::phase2() {return simplex(0); }//執行兩階段單純形算法 void LinearProgram::solve() {cout<<endl<<"* * * 線性規劃---單純形算法 * * *"<<endl<<endl;error = compute();switch(error){case 0:output();break;case 1:cout<<"輸入數據錯誤--"<<endl;break;case 2:cout<<"無界解--"<<endl;break;case 3:cout<<"無可行解--"<<endl;}cout<<"計算結束"<<endl; }//輸出結果 void LinearProgram::output() {int width = 8,*basicp;doube zero = 0.0;basicp = new int[n+m+1];setbasic(basicp);cout.setf(ios::fixed|ios::showpoint|ios::right);cout.precision(4);sstats();//?????這句話是執行什么了?cout<<endl<<"最優值:"<<-minmax*a[0][0]<<endl<<endl;cout<<"最優解:"<<endl<<endl;for(int j=1; j<=n; j++){cout<<"x"<<j<<" =";if(basicp[j]!=0){cout<<setw(width)<<a[basicp[j]][0];}else{cout<<setw(width)<<zero;}cout<<endl;}cout<<endl;delete []basicp; }int main() {return 0; }?
轉載于:https://www.cnblogs.com/dyllove98/p/3178063.html
總結
以上是生活随笔為你收集整理的0050算法笔记——【线性规划】单纯形算法(未完全实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个不错的windows编程网址
- 下一篇: Ant在MyEclipse中的配置总结