线性规划之单纯形解法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);
    }
image.png

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容