单纯形法C++实现

作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4156685.html

使用单纯型法来求解线性规划,输入单纯型法的松弛形式,是一个大矩阵,第一行为目标函数的系数,且最后一个数字为当前轴值下的 z 值。下面每一行代表一个约束,数字代表系数每行最后一个数字代表 b 值。

算法和使用单纯性表求解线性规划相同。

对于线性规划问题:

Max      x1 + 14* x2 + 6*x3

s . t .  x1 + x2 + x3 <= 4

    x1<= 2

    x3 <= 3

    3*x2 + x3 <= 6

    x1,x2,x3 >= 0

我们可以得到其松弛形式:

Max  x1 +  14*x2 + 6*x3
s.t.   x1 +  x2   + x3   + x4 = 4
    x1               + x5 = 2
            x3           + x6 = 3
         3*x2   + x3               + x7 = 6
    x1 , x2 , x3 , x4 , x5 , x6 , x7 ≥ 0

我们可以构造单纯性表,其中最后一行打星的列为轴值。

单纯性表
x1 x2 x3 x4 x5 x6 x7 b
c1=1 c2=14 c3=6 c4=0 c5=0 c6=0 c7=0 -z=0
1 1 1 1 0 0 0 4
1 0 0 0 1 0 0 2
0 0 1 0 0 1 0 3
0 3 1 0 0 0 1 6
      * * * *  

在单纯性表中,我们发现非轴值的x上的系数大于零,因此可以通过增加这些个x的值,来使目标函数增加。我们可以贪心的选择最大的c,再上面的例子中我们选择c2作为新的轴,加入轴集合中,那么谁该出轴呢?

其实我们由于每个x都大于零,对于x2它的增加是有所限制的,如果x2过大,由于其他的限制条件,就会使得其他的x小于零,于是我们应该让x2一直增大,直到有一个其他的x刚好等于0为止,那么这个x就被换出轴。

我们可以发现,对于约束方程1,即第一行约束,x2最大可以为4(4/1),对于约束方程4,x2最大可以为3(6/3),因此x2最大只能为他们之间最小的那个,这样才能保证每个x都大于零。因此使用第4行,来对各行进行高斯行变换,使得二列第四行中的每个x都变成零,也包括c2。这样我们就完成了把x2入轴,x7出轴的过程。变换后的单纯性表为:

单纯性表
x1 x2 x3 x4 x5 x6 x7 b
c1=1 c2=0 c3=1.33 c4=0 c5=0 c6=0 c7=-4.67 -z=-28
1 0 0.67 1 0 0 -0.33 2
1 0 0 0 1 0 0 2
0 0 1 0 0 1 0 3
0 1 0.33 0 0 0 0.33 2
    * * *    

继续计算,我们得到:

单纯性表
x1 x2 x3 x4 x5 x6 x7 b
c1=-1 c2=0 c3=0 c4=0 c5=-2 c6=0 c7=0 -z=-32
1.5 0 1 1.5 0 0 -0.5 3
1 0 0 0 1 0 0 2
0 0 1 0 0 1 0 3
0 1 0.33 0 0 0 0.33 2
    * * *    

此时我们发现,所有非轴的x的系数全部小于零,即增大任何非轴的x值并不能使得目标函数最大,从而得到最优解32.

整个过程代码如下所示:

  1 #include <cstdio>
  2 #include <climits>
  3 #include <cstdlib>
  4 #include <iostream>
  5 #include <cstring>
  6 #include  <vector>
  7 #include  <fstream>
  8 #include <set>
  9 using namespace std;
 10 vector<vector<double> > Matrix;
 11 double Z;
 12 set<int> P;
 13 size_t cn, bn;
 14
 15 bool Pivot(pair<size_t, size_t> &p)//返回0表示所有的非轴元素都小于0
 16 {
 17     int x = 0, y = 0;
 18     double cmax = -INT_MAX;
 19     vector<double> C = Matrix[0];
 20     vector<double> B;
 21
 22     for( size_t i = 0 ; i < bn ; i++ )
 23     {
 24         B.push_back(Matrix[i][cn-1]);
 25     }
 26
 27     for( size_t i = 0 ; i < C.size(); i++ )//在非轴元素中找最大的c
 28     {
 29         if( cmax < C[i] && P.find(i) == P.end())
 30         {
 31             cmax = C[i];
 32             y = i;
 33         }
 34     }
 35     if( cmax < 0 )
 36     {
 37         return 0;
 38     }
 39
 40     double bmin = INT_MAX;
 41     for( size_t i = 1 ; i < bn ; i++ )
 42     {
 43         double tmp = B[i]/Matrix[i][y];
 44        if( Matrix[i][y] != 0 && bmin > tmp )
 45        {
 46            bmin = tmp;
 47            x = i;
 48        }
 49     }
 50
 51     p = make_pair(x, y);
 52
 53     for( set<int>::iterator it = P.begin() ; it != P.end() ; it++)
 54     {
 55         if( Matrix[x][*it] != 0 )
 56         {
 57             //cout<<"erase "<<*it<<endl;
 58             P.erase(*it);
 59             break;
 60         }
 61     }
 62     P.insert(y);
 63     //cout<<"add "<<y<<endl;
 64     return true;
 65 }
 66
 67 void pnt()
 68 {
 69     for( size_t i = 0 ; i < Matrix.size() ; i++ )
 70     {
 71         for( size_t j = 0 ; j < Matrix[0].size() ; j++ )
 72         {
 73             cout<<Matrix[i][j]<<"\t";
 74         }
 75     cout<<endl;
 76     }
 77     cout<<"result z:"<<-Matrix[0][cn-1]<<endl;
 78 }
 79
 80 void Gaussian(pair<size_t, size_t> p)//行变换
 81 {
 82     size_t  x = p.first;
 83     size_t y = p.second;
 84     double norm = Matrix[x][y];
 85     for( size_t i = 0 ; i < cn ; i++ )//主行归一化
 86     {
 87         Matrix[x][i] /= norm;
 88     }
 89     for( size_t i = 0 ; i < bn && i != x; i++ )
 90     {
 91         if( Matrix[i][y] != 0)
 92         {
 93             double tmpnorm = Matrix[i][y];
 94             for( size_t j = 0 ; j < cn ; j++ )
 95             {
 96                 Matrix[i][j] = Matrix[i][j] - tmpnorm * Matrix[x][j];
 97             }
 98         }
 99     }
100 }
101
102 void solve()
103 {
104     pair<size_t, size_t> t;
105     while(1)
106     {
107
108         pnt();
109         if( Pivot(t) == 0 )
110         {
111             return;
112         }
113         cout<<t.first<<" "<<t.second<<endl;
114         for( set<int>::iterator it = P.begin(); it != P.end()  ; it++ )
115         {
116             cout<<*it<<" ";
117         }
118         cout<<endl;
119         Gaussian(t);
120     }
121 }
122
123 int main(int argc, char *argv[])
124 {
125     ifstream fin;
126     fin.open("./test");
127     fin>>cn>>bn;
128     for( size_t i = 0 ; i < bn ; i++ )
129     {
130         vector<double> vectmp;
131         for( size_t j = 0 ; j < cn ; j++)
132         {
133             double tmp = 0;
134             fin>>tmp;
135             vectmp.push_back(tmp);
136         }
137         Matrix.push_back(vectmp);
138     }
139
140     for( size_t i = 0 ; i < bn-1 ; i++ )
141     {
142         P.insert(cn-i-2);
143     }
144     solve();
145 }
146 /////////////////////////////////////
147 //glpk input:
148 ///* Variables */
149 //var x1 >= 0;
150 //var x2 >= 0;
151 //var x3 >= 0;
152 ///* Object function */
153 //maximize z: x1 + 14*x2 + 6*x3;
154 ///* Constrains */
155 //s.t. con1: x1 + x2 + x3 <= 4;
156 //s.t. con2: x1  <= 2;
157 //s.t. con3: x3  <= 3;
158 //s.t. con4: 3*x2 + x3  <= 6;
159 //end;
160 /////////////////////////////////////
161 //myinput:
162 //8 5
163 //1 14 6 0 0 0 0 0
164 //1 1 1 1 0 0 0 4
165 //1 0 0 0 1 0 0 2
166 //0 0 1 0 0 1 0 3
167 //0 3 1 0 0 0 1 6
168 /////////////////////////////////////

时间: 2024-10-25 14:24:44

单纯形法C++实现的相关文章

单纯形法求解线性规划问题(C++实现代码)

1 单纯形法 (1) 单纯形法是解线性规划问题的一个重要方法. 其原理的基本框架为: 第一步:将LP线性规划变标准型,确定一个初始可行解(顶点). 第二步:对初始基可行解最优性判别,若最优,停止:否则转下一步. 第三步:从初始基可行解向相邻的基可行解(顶点)转换,且使目标值有所改善-目标函数值增加,重复第二和第三步直到找到最优解. (2) 用程序进行运算前,要将目标函数及约束方程变成标准形式. 于非标准形式须作如下变换: a) 目标函数为极小值min z=CX时,转换为max z=-CX形式:

BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]

1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3975  Solved: 2421[Submit][Status][Discuss] Description 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难 题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完成,其中第i 天至少需要 Ai 个人. 布布通过了解得知,一共有M 类志

修正单纯形法&#183;优化算法实现&#183;Java

修正单纯性法 代码如下: 舍去了输入转化的内容,主要包含算法关键步骤. public class LPSimplexM { private static final double inf = 1e9; private int n; // 约束个数 private double[][] A; // 输入函数参数 private double[] b; // 约束值 private double[] c; // 目标函数系数 private double Z; // 目标值 private void

运筹学——线性规划及单纯形法求解

运筹学——线性规划及单纯形法求解 1. 线性规划的概念 线性规划是研究在一组线性不等式或等式约束下使得某一线性目标函数取最大(或最小)的极值问题. 2. 线性规划的标准形 特点:目标函数求极大:等式约束:变量非负. 令 则线性规划标准形的矩阵表达式为: 约定: 如何化标准形: (I) 目标函数实现极大化,即,令,则: (II)约束条件为不等式 约束条件为“” 不等式,则在约束条件的左端加上一个非负的松弛变量: 约束条件为“” 不等式,则在约束条件的左端减去一个非负的松弛变量. (III)若存在无

【工程优化】最优化算法--牛顿法、阻尼牛顿法及单纯形法

牛顿法 使用条件:目标函数具有二阶导数,且海塞矩阵正定. 优缺点: 收敛速度快.计算量大.很依赖初始点的选择. 算法的基本步骤: 算法流程图: 阻尼牛顿法 与牛顿法基本相同,只是加入了一维精确搜索: 优缺点:改善了局部收敛性. 我们假设要求f=(x-1)*(x-1)+y*y的最小值,具体算法实现如下,只需要运行NTTest.m文件,其它函数文件放在同一目录下即可: 1.脚本文件NTTest.m clear all clc syms x y f=(x-1)*(x-1)+y*y; var=[x y]

单纯形法与线性规划

Preface 好久之前就想学学单纯形法了,因为据说用途非常广泛,而且最近恰好要做有关的题目 感觉还是挺高级的一个姿势吧,以下参考自一,二以及2016年的集训队论文,最后看的是bzt的板子,默认大家都知道线性规划是什么且具有一定线性代数的基础(好把没有也没有关系) 线性规划的标准型与松弛型 线性规划的标准型一般是这样的: 而松弛型是这样的: 桥豆麻袋,上面的标准型我能理解,这个松弛型是个什么鬼东西,怎么让变量更多了呢? 不要慌我们来观察一下,标准型简洁是简洁,但是它的约束符号是不等号(小于等于)

POJ1275 Cashier Employment[差分约束系统 || 单纯形法]

Cashier Employment Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7997   Accepted: 3054 Description A supermarket in Tehran is open 24 hours a day every day and needs a number of cashiers to fit its need. The supermarket manager has hir

BZOJ 3112: [Zjoi2013]防守战线 [单纯形法]

题目描述 战线可以看作一个长度为n 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第i 号位置上建一座塔有Ci 的花费,且一个位置可以建任意多的塔,费用累加计算.有m 个区间[L1, R1], [L2, R2], …, [Lm, Rm],在第i 个区间的范围内要建至少Di 座塔.求最少花费. 输入输出格式 输入格式: 第一行为两个数n, m. 接下来一行,有n 个数,描述C 数组. 接下来m 行,每行三个数Li,Ri,Di,描述一个区间. 输出格式: 仅包含一行,一个数,为最少花费. 输入输

单纯形法

如果目标函数中所有系数都非正,那么显然这些变量直接取0是最优的,所以此时答案为即为常数项. 我们要做的就是通过转化把目标函数的系数全部搞成非负. 思路就是用非基变量替换基变量. 先找到一个目标函数中系数为正的变量,在所有限制中找到一个对它最紧的限制. 用这一行中的其他变量来代换他,显然会把它代换成一个系数全部是负的式子. 然后用这个式子代换每一个限制中的该变量,这样可以使原来的一个基变量变为非基变量. 然后,可以证明的是,通过有限步这样的操作,即可使目标函数所有系数非正. 再加一个鬼畜的对偶定理