关闭

线性规划之单纯性算法

标签: 数学
3809人阅读 评论(0) 收藏 举报
分类:
线性函数:按比例,一阶导数为常数的函数。
松弛变量:引入新的变量,且保持变量间的关系不变。
提到线性规划,自己最先想起的是高中的各种数学题。
线性规划问题的标准形式:

用松弛变量技术把不等式化成等式:


单纯性算法的思想:
从一个基本可行解出发,寻找能使得目标函数更优的另一个解,迭代下去直到找不到。使用这种方法避免大量的无用比较。
例子:
FOREVER284LOVE的线性规划与单纯形法》
看到的一题,以它为例:
某工厂在计划期内要安排生产I、  II两种产品, 已知生产单位产品所需的设备台时及A、B两种原材 料的损耗,如表所示:


        I

       II


      设备

  原材料A

  原材料B

        1

        4

        0

       2

       0

       4

   8台时

    16kg

    12kg

该工厂每生产一件产品Ⅰ可获利2元,每生产一件产品Ⅱ可获利3元,问应如何安排计划使该工厂获利最多?
解:列出标准形式:

所以:

称Z表达式中的变量为非基变量(x1,x2),约束方程中剩余的变量是基变量 (x3,x4,x5)
当非基变量全是0时,Z有一个X解。这一个解作为初始解。想要让Z变大,那么正整数系数的变量一定要变大。
可以选一个最大系数的变量x2,那么x1随着x2变大将变成0,那么从约束方程可以看出,X5先变成0,故把X1和X5作为新的非基变量。
有:

存在正系数说明目标函数还能变大。令x5=0,从约束方程可以看出,x1最大取2,此时x3=0。那么新的非基变量就是x3, x5.于是得到:

重复刚刚的步骤,得到:

当x3=x4=0时得到最优解z=14
把刚刚的过程表格化:(表格化思想来自《组合数学及应用》)



我们发现,事实上,一个基本变量和一个非基本变量互换后得到了下一个方程组。
寻找互换的非基本变量:对应的Z行系数是负数的,选择它,有多个负数就选择最小的那个。对应的非基本变量就是选择项。
寻找互换的基本变量:非基本变量增大,基本变量减小,谁先变成0,谁就是基本变量。
数值元素变化规律:称参与互换的非基变量所在列是主元列,基本变量所在行是主元行。
设当前的主元行是r,主元列是c,主元为, 各个位置的元素值是

设投影列元素a,投影行元素b。投影是相对主元行和主元列而言,上图中16的投影行元素是12,投影列元素是0
那么其他的元素就是:
后续变化:







嗯嗯,就是这个流程。

设那些有数字元素构成一个二维矩阵a[][]. 设n个变量,m个约束条件。
那么修改数字矩阵的部分写成程序就是 
    a[r][c] = 1 / a[r][c];
    for(int j = 0; j <= n; j++) if(j != c) a[r][j] *= a[r][c];
    for(int i = 0; i <= m; i++)
    if(i != r) {
      for(int j = 0; j <= n; j++)
        if(j != c) a[i][j] -= a[i][c] * a[r][j];
      a[i][c] = -a[i][c] * a[r][c];
    }
寻找基本变量和非基本变量,判断有界、无解、无界部分是真不会写了,参考别人的模板。

献上一题:
uva 10498 - Happiness
大意:买N件物品,每个人对每件物品有自己的满意度,且有一个满意度和的限制。每一件物品有自己的价格,问能花费的最多的钱。

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxm = 500; // 约束数目上限
const int maxn = 500; // 变量数目上限
const double INF = 1e100;
const double eps = 1e-10;

struct Simplex {
  int n; // 变量个数
  int m; // 约束个数
  double a[maxm][maxn]; // 输入矩阵
  int B[maxm], N[maxn]; // 算法辅助变量

  void calc(int r, int c) {
    swap(N[c], B[r]);
    a[r][c] = 1 / a[r][c];
    for(int j = 0; j <= n; j++) if(j != c) a[r][j] *= a[r][c];
    for(int i = 0; i <= m; i++)
    if(i != r) {
      for(int j = 0; j <= n; j++)
        if(j != c) a[i][j] -= a[i][c] * a[r][j];
      a[i][c] = -a[i][c] * a[r][c];
    }
  }

  bool check() {
    while(1) {
      int r, c;
      double p = INF;
      for(int i = 0; i < m; i++){
         if(a[i][n] < p) {
            r=i;
            p = a[r][n];  // 最右边的常数列
         }
      }
      if(p > -eps) return true;  // 都是正数的话可行。
      p = 0;
      for(int i = 0; i < n; i++) {
          if(a[r][i] < p){
             c=i;
             p = a[r][c];  // 找最小列
          }
      }
      if(p > -eps) return false;  // r对应的所有列都是正数,没有负数,无解。
      p = a[r][n]/a[r][c];
      for(int i = r+1; i < m; i++)
        if(a[i][c] > eps) {
           double v = a[i][n] / a[i][c];
           if(v < p) {
               r = i;
               p = v;
           }
      }
      calc(r, c);
    }
  }

  // 解有界返回1,无解返回0,无界返回-1。b[i]为x[i]的值,ret为目标函数的值
  int simplex(int n, int m, double x[maxn], double& ret) {
    this->n = n;
    this->m = m;
    for(int i = 0; i < n; i++) N[i] = i;
    for(int i = 0; i < m; i++) B[i] = n+i;
    if(!check()) return 0;
    while(1){
      int r, c;
      double p = 0;
      for(int i = 0; i < n; i++) if(a[m][i] > p) {
            c = i;
            p = a[m][c];
      }
      if(p < eps) {
        for(int i = 0; i < n; i++) if(N[i] < n) x[N[i]] = 0;
        for(int i = 0; i < m; i++) if(B[i] < n) x[B[i]] = a[i][n];
        ret = -a[m][n];
        return 1;
      }
      p = INF;
      for(int i = 0; i < m; i++) if(a[i][c] > eps) {
        double v = a[i][n] / a[i][c];
        if(v < p) { r = i; p = v; }
      }
      if(p == INF) return -1;
      calc(r, c);
    }
  }
};

Simplex solver;
int main()
{
    //freopen("cin.txt","r",stdin);
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        for(int i = 0; i < n; i++) scanf("%lf", &solver.a[m][i]); // 目标函数
        solver.a[m][n] = 0;
        for(int i = 0; i < m; i++)
           for(int j = 0; j < n+1; j++)
               scanf("%lf", &solver.a[i][j]);
        double ans,x[maxn];
        solver.simplex(n,m,x,ans);
        ans *= m;
        //printf("Nasa can spend %d taka.\n", int(ans+0.5)); // 至少花费的:3.008-->4
        printf("Nasa can spend %d taka.\n", (int)floor(ans + 1 - eps));
    }
    return 0;
}

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

算法导论之线性规划

线性规划,充斥着运筹学,在图的单源最短路径求解差分约束系统就是用到线性规划。怎么样问题可以建模为线性规划来解决呢?在给定的有限的资源和竞争约束情况下,取得最大化或最小化目标的问题。导论中给出政治竞选问题、航空航线调度问题、钻井采油问题。最大化或最小化目标是函数的因变量,自变量就是资源的约束因素,其函...
  • fjssharpsword
  • fjssharpsword
  • 2016-11-17 09:21
  • 3182

线性规划

原文地址:http://blog.sina.com.cn/s/blog_61e8042b0100eepi.html 在数学中,线性规划 (Linear Programming,简称LP) 问题是目标函数和约束条件都是线性的最优化问题。 线性规划是最优化问题中的重要领...
  • xiaogugood
  • xiaogugood
  • 2014-01-14 17:12
  • 14425

线性规划算法

  • 2015-02-08 20:44
  • 188KB
  • 下载

线性规划算法原理介绍

线性规划定义: 求满足约束的最优目标,目标是变量的线性函数,约束是变量的相等或不等表达式。 单纯形算法 1 松弛变量 为将不等式转化为等式添加的非负变量 比如 将f(xi) >0 变成 yj= f(xi) ,那么xj就是松弛变量 主元操作(pivot) 1 任意在目标函...
  • mxlwd168
  • mxlwd168
  • 2017-01-11 21:35
  • 209

线性规划:单纯形算法

作者 dylanFrank(滔滔) 转载请联系作者 原文链接:http://blog.csdn.net/Dylan_Frank/article/details/77876006 这里简要总结一下线性规划的单纯形算法,做如下几个方面的总结,其余以后再来填坑. 几何表示 标准型的代数解法 其他情...
  • Dylan_Frank
  • Dylan_Frank
  • 2017-09-07 00:18
  • 686

单纯形算法求解线性规划问题(依据《算法导论》实现)

#include #include #include #include #include using namespace std; const int MAXN = 100; const double INF = 999999.0; const double EPS = 1e-9; do...
  • niuxiunan
  • niuxiunan
  • 2015-11-30 16:05
  • 1543

线性规划问题的新算法

  • 2016-04-26 21:53
  • 5.28MB
  • 下载

常见算法及问题场景——线性规划

数据模型1、约束条件及目标函数 2、约束条件所表示的可行域 3、在可行域内求目标函数的最优解及最优值理论体系几何上,线性约束条件的集合相当于一个凸包或凸集,叫做可行域。 目标函数亦是线性的,所以其极值点会自动成为最值点。而线性目标函数暗示其最优解只会出现在其可行域的边界点中。两种情况下无解: ...
  • a345017062
  • a345017062
  • 2016-09-06 16:35
  • 529

线性规划算法

  • 2015-05-20 15:47
  • 623KB
  • 下载

【高级算法】单纯形法求解线性规划问题(C++实现)

1 单纯形法(1) 单纯形法是解线性规划问题的一个重要方法。 其原理的基本框架为: 第一步:将LP线性规划变标准型,确定一个初始可行解(顶点)。 第二步:对初始基可行解最优性判别,若最优,停止;否则转下一步。 第三步:从初始基可行解向相邻的基可行解(顶点)转换,且使目标值有所改善—目标函数...
  • zhoubin1992
  • zhoubin1992
  • 2015-07-16 19:40
  • 7177
    个人资料
    • 访问:331297次
    • 积分:8856
    • 等级:
    • 排名:第2517名
    • 原创:575篇
    • 转载:13篇
    • 译文:0篇
    • 评论:36条
    我的链接
    最新评论