1. 程式人生 > >線性規劃之單純形解法Java實現

線性規劃之單純形解法Java實現

單純形法

理解完這個演算法後大家也可以打一下,打碼過程中,會有很多很多的錯誤要排查,編碼一小時,排錯三小時,不過從中可以練習到蠻多的(執行截圖在文末)
  • 輸入線性規劃標準型的資料(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);
    }

這裡寫圖片描述這裡寫圖片描述