線性規劃之單純形解法Java實現
阿新 • • 發佈:2019-02-16
單純形法
理解完這個演算法後大家也可以打一下,打碼過程中,會有很多很多的錯誤要排查,編碼一小時,排錯三小時,不過從中可以練習到蠻多的(執行截圖在文末)
- 輸入線性規劃標準型的資料(n個變數,m個約束條件)
- C //價值係數向量
- X //決策變數向量
- A //工藝係數矩陣
- b //資源常數
- yita //檢驗數
- theta //b除以換入變數在每行的係數,即單純形表最右端引數
找基可行解
- 簡單的拿最後m個決策變數,後期可優化
判斷是否最優解:計算並判斷是否每一個檢驗數yita都小於等於0
- 是
- 輸出最優解:max z = CX
- 否
- 確定換入變數
- 檢驗數大於0中,檢驗數最大的非基變數
- 確定換出變數
- 計算theta
- 判斷是否線性規劃結果為無界解:theta的係數是否均小於或等於0
- 是
- 終止運算,輸出結果為無界解
- 否
- 取theta[i]中大於0且最小的行所對應的基變數作為換出變數
- 是
- 旋轉運算
- 換入變數的所對應的方程中左右兩邊同除換入變數的係數
- 再次迴圈,重新判斷是否最優解
- 確定換入變數
- 是
所有函式
- void inputNums() //輸入資料
- void findBasedVariables() //找基變數
- bool isOptimum() //是否最優解
- int getVariableIn() //確定換入變數
- int getVariableOut() //確定換出變數
- void updateVectors() //更新旋轉運算後的矩陣
- private static void printVector() //輸出係數矩陣
- void printOptimun() //輸出最優解
先在main函式中寫好主要邏輯,再具體實現
public static void main(String[] args) {
//輸入資料,為了簡單起見,我們的資料直接在程式碼中敲入,這個函式等測試完後加
inputNums();
//找初始基變數
findBasedVariables();
//判斷是否最優解
while (!isOptimum()) {
//找換入變數
idxOfIn = getVariableIn();
printVector();
//找換出變數
idxOfOut = getVariableOut();
//如果idxOfOut返回-1,則該線性規劃問題有無界解
if(idxOfOut == -1)
return;
//旋轉運算,更新矩陣
updateVectors();
printVector();
System.out.println("\n");
}
//輸出最優解
printOptimum();
}
全域性變數
private static double A[][] = { { 1, 2, 1, 0, 0 },
{ 2, 1, 0, 1, 0 },
{ 4, 3, 0, 0, 1 } };// 係數矩陣
private static int m = A.length; //m個方程
private static int n = A[0].length; //n個決策變數
private static double C[] = { 3, 2, 0, 0, 0 }; // 價值係數
private static double b[] = { 5, 4 ,9}; // 資源常數
private static double theta[] = new double[m]; //b的檢驗數
private static int basedVar[] = new int[m]; // 基變數,存基變數的下標,從1開始標號(區別於陣列儲存習慣)
private static double yita[] = new double[n]; //檢驗數,有n個決策變數的檢驗數
private static double result = -1; //結果
private static int idxOfIn = -1; //換入變數的下標
private static int idxOfOut = -1; //換出變數的下標
inputNums()
// 輸入資料,先在程式碼中寫入資料,後期再加,先把初始檢驗數賦值為價值係數
private static void inputNums() {
for (int i = 0; i < yita.length; i++) {
yita[i] = C[i]; //yita為檢驗數
}
}
findBasedVariables()
// 找基變數,簡單的拿最後m個決策變數,後期可優化,儲存在basedVar陣列中
private static void findBasedVariables() {
//取n個決策變數的最後m個作基變數
for (int i = 0; i < m; i++) {
//basedVar[i] = n-i;
//改變存放順序為正敘
basedVar[m-i-1] = n-i ;
}
System.out.println("基變數為:");
for (int i = 0; i < basedVar.length; i++) {
System.out.print("x" + (basedVar[i]) + "\t");
}
System.out.println();
}
isOptimum()
// 判斷是否最優解,並計算檢驗數yita向量
private static boolean isOptimum() {
//換入變數代替換出變數
if(idxOfIn != -1 && idxOfOut != -1){
//第idxOfOut個基變數換為x idxOfIn
basedVar[idxOfOut] = idxOfIn+1;
}
//更新檢驗數
for (int i = 0; i < n; i++) {
double temp = yita[i];
for (int j = 0; j < m; j++) {
temp -= A[j][i] * C[basedVar[j] -1];
}
yita[i] = temp;
}
boolean hasPossitiveYita = false;
for (int i = 0; i < yita.length; i++) {
if(yita[i] > 0)
hasPossitiveYita = true;
}
System.out.println("是否最優解:" + !hasPossitiveYita);
return !hasPossitiveYita;
}
getVariableIn()
// 確定換入變數,返回換入變數的下標-1
private static int getVariableIn() {
//遍歷檢驗數
int index = 0;
System.out.println("檢驗數如下:");
for (int i = 0; i < yita.length; i++) {
System.out.print(yita[i] + "\t");
if(yita[i] > yita[index]){
index = i;
}
}
System.out.println();
System.out.println("換入變數是x" + (index+1));
return index;
}
getVariableOut()
// 確定換出變數,返回換出變數在基變數向量中的下標
private static int getVariableOut() {
System.out.println("theta:");
for (int i = 0; i < m; i++) {
if( Double.compare(A[i][idxOfIn], 0) != 0)
theta[i] = b[i] / A[i][idxOfIn];
else {
theta[i] = 0;
}
System.out.print(theta[i] + "\t");
}
System.out.println();
int index = 0;
for (int i = 0; i < theta.length; i++) {
if(theta[i] <= 0){
System.out.println("該方程有無界解...");
return -1;
}else {
if(theta[i] < theta[index])
index = i;
}
}
System.out.println("換出變數是:x" + (basedVar[index]));
return index;
}
updateVectors()
// 更新旋轉運算後的矩陣
private static void updateVectors() {
//m個方程,n個變數
//將主元係數化為1
//防止迭代中主元的值被改變後引起 其它係數除主元的新值,將主元的原值存於temp
double temp = A[idxOfOut][idxOfIn];
for (int i = 0; i < n; i++) {
A[idxOfOut][i] /= temp;
}
b[idxOfOut] /= temp;
System.out.println("\n將主元係數化為1");
printVector();
//主元所在列其餘元素係數要化為0,即:主元列中,非主元所在行均減去 主元係數分之一*A[m][n]
for (int i = 0; i < m; i++) {
//若是換出變數所對應行,則該行不用換算
double temp1 = A[i][idxOfIn]/A[idxOfOut][idxOfIn];
if(i != idxOfOut){
for (int j = 0; j < n; j++) {
A[i][j] -= A[idxOfOut][j]*temp1;
}
b[i] -= b[idxOfOut] * temp1;
}
}
System.out.println("完成一次矩陣旋轉運算...");
}
printVector()
//輸出係數矩陣
private static void printVector() {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
System.out.print(A[i][j] + "\t");
}
System.out.println(b[i]);
}
System.out.println("-----------------------------------------------");
}
printOptimum()
//輸出最優解
private static void printOptimum() {
result = 0;
for (int i = 0; i < basedVar.length; i++) {
result += C[basedVar[i]-1] * b[i];
}
System.out.println("最優解:z = " + result);
}