线性规划标准型转化及单纯性算法之线性规划网络流(工厂最大收益)

线性规划问题

(1) 确定决策变量
(2) 确定目标函数
(3) 找出约束条件
(4) 求最优解

简单问题
例:
在这里插入图片描述
图片来源:《趣学算法》陈小玉-人民邮电出版社

在这里插入图片描述
 变量满足约束条件的一组值称为线性规划的一个可行解
 所有可行解构成集合称为线性规划问题的可行区域
 使得目标函数取得极值得可行解称为最优解
 在最优解处目标函数的值称为最优值

线性规划问题解的情况
有唯一最优解 有无数个最优解 没有最优解

线性规划标准型
在这里插入图片描述

线性规划标准型转化方法

在这里插入图片描述

单纯性算法

基本变量
每个约束条件中的系数为正且只出现在一个约束中的变量。
非基本变量:
除基本变量外的变量全部为非基本变量。
基本可行解
满足标准形式约束条件的可行解称为基本可行解。
检验数:
目标函数中非基本变量的系数。

线性规划基本定理:
定理1:最优解判别定理
若目标函数中关于非基本变量的所有系数(检验数Cj )小于等于0,则当前基本可行解就是最优解。
定理2:无穷多最优解判别定理
若目标函数中关于非基本变量的所有检验数小于等于0,同时存在某个非基本变量的检验数等于0,则线性规划问题有无穷多个最优解。
定理3:无界解定理
如果某个检验数Cj大于0,而Cj所对应的列向量的各分量a1j,a2j,…,amj都小于等于0,则线性规划问题有无界解。
算法步骤
(1) 建立初始单纯形表
在这里插入图片描述
在这里插入图片描述
(2) 判断是否得到最优解
在这里插入图片描述
(3) 选入基变量
在这里插入图片描述
在这里插入图片描述
(4) 选离基变量
在这里插入图片描述
在这里插入图片描述
(5) 换基变换
在这里插入图片描述
在这里插入图片描述
(6) 计算新的单纯形表
在这里插入图片描述

(7) 判断是否得到最优解
在这里插入图片描述

实例

/*问题引入
 *工厂最大收益--单纯形算法
 *某工厂共有3个加工车间、第1个车间用1个单位的原料N可以加工出5个单位的A或2个单位的产品B
 *产品A直接出售、售价为10元。
 *产品B直接出售、售价为16元。
 *如果在第2车间继续加工产品A,要额外加工费5元、加工后售价为19元。
 *如果在第3车间继续加工产品B,要额外加工费4元、加工后售价为24元。
 *原料N的单位购入价为5元。
 *每工时工资为15元。
 *1车间加工一个单位N需要0.05个工时。
 *2车间加工一个单位需要0.1个工时。
 *3车间加工一个单位需要0.08工时。
 *每个月最多可以得到12000单位的原料N。
 *工时最多为1000工时。
 *如何安排生产,才能使得工厂的收益最大呢?
 * */
/*问题分析
 * x1:卖出A x2:卖出二次加工的A x3:卖出的B x4:卖出二次加工的B x5:1车间共使用原料N的总单位
 *目标函数:max z=10*x1+12.5*x2+16*x3+18.8*x4-5.75*x5
 *约束条件:
 *x1+x2-5*x5=0
 *x3+x4-2*x5=0
 *x5<=12000
 *0.1*x2+0.08*x4+0.05*x5<=1000
 *xi>=0(i=0,1,2,3,4,5)
 *
 *
 *转化为标准型
 *max z=10*x1+12.5*x2+16*x3+18.8*x4-5.75*x5
 *
 *
 *x1+x2-5*x5=0
 *x3+x4-2*x5=0
 *x5+x6=12000
 *0.1*x2+0.08*x4+0.05*x5+x7=1000
 *xi>=0(i=1,2,3,4,5,6,7)
 *
 *基本变量:x1\x3\x6\x7
 *非基本变量:x2\x4\x5
 *
 *目标函数由非基本变量表示
 *x1=5*x5-x2  x3=2*x5-x4
 *目标函数:max z=2.5*x2+2.8*x4+76.25*x5
 * */

代码实现

#include<iostream>
#include<math.h>
using namespace std;
float kernel[100][100];//存储非单纯形表
char FJL[100]={};//非基本变量
char JL[100]={};//基本变量
int m,n;//m:非基本变量的个数 n:基本变量的个数

void print();//打印表
void DCXA();//单纯形算法

int main(void){
    cout<<"请输入非基本变量的个数与非基本变量的下标\n";
    cin>>m;
    for(int i=1;i<=m;i++){
        cin>>FJL[i];
    }
    cout<<"请输入基本变量个数与非基本变量的下标\n";
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>JL[i];
    }
    cout<<"请输入约束标准型初始单纯形表参数\n";
    for(int i=0;i<=n;i++){
        for(int j=0;j<=m;j++){
            cin>>kernel[i][j];
        }
    }
    print();
    DCXA();
    return 0;
}


//打印表
void print(){
    cout<<"单纯形表\n";
    cout<<"       b ";
    for(int i=1;i<=n;i++){
        cout<<"      x"<<FJL[i];
    }
    cout<<"\n";
    cout<<"c ";
    for(int i=0;i<=n;i++){
        if(i>=1){
            cout<<"x"<<JL[i];
        }
        for(int j=0;j<=m;j++){
            cout<<"      "<<kernel[i][j]<<" ";
        }
        cout<<"\n";
    }

}


//单纯形算法
void  DCXA(){
    float max1;//存放最大检验数
    float max2;//存放最大正检验数对应的基本变量的最大系数
    int enter=-1;//入基变量下标
    int quit=-1;//离基变量下标
    float min=0;
    while(1){//循环迭代直到找到解或者确定无解
        max1=0;
        max2=0;
        min=100000000;
        //算法步骤1:寻找入基变量(检验数最大的那一列) 目标函数系数最大
        for(int i=1;i<=m;i++){
            if(max1<kernel[0][i]){
                max1=kernel[0][i];
                enter=i;
            } 
        }
        //算法步骤2:判断最优解情况
        //如果所有检验数<=0,则满足最优解条件
        if(max1<=0){
            cout<<"获得最优解: "<<kernel[0][0]<<"\n";
            print();
            return;//停止求解
        }
        //如果正检验数对应的列都小于等于0,则无界
        for(int j=1;j<=m;j++){
            max2=0;
            if(kernel[0][j]>0){//检验数为正
                for(int i=1;i<=n;i++){
                    if(max2<kernel[i][j]){
                        max2=kernel[i][j];
                    }
                }
                if(max2==0){
                    cout<<"解无界\n";
                    return;//停止求解
                }
            }
        }

        //算法步骤3:找离基行(常数列/入基列正比值最小对应的行)
        for(int i=1;i<=n;i++){
            float temp=kernel[i][0]/kernel[i][enter];
            if(temp>0&&temp<min){
                min=temp;
                quit=i;
            }
        }

        //算法步骤4:变基变换
        char temp=FJL[enter];
        FJL[enter]=JL[quit];
        JL[quit]=temp;


        //算法步骤5:计算新的单纯形表
        for(int i=0;i<=n;i++){
            if(i!=quit){
                for(int j=0;j<=m;j++){
                    if(j!=enter){
                        if(i==0&&j==0){//[0,0]位置
                            kernel[i][j]=kernel[i][j]+kernel[i][enter]*kernel[quit][j]/kernel[quit][enter];
                        }else{//一般位置
                            kernel[i][j]=kernel[i][j]-kernel[i][enter]*kernel[quit][j]/kernel[quit][enter];
                        }
                    }
                }
            }
        }

        //入基列的元素
        for(int i=0;i<=n;i++){
            if(i!=quit){
                kernel[i][enter]=-kernel[i][enter]/kernel[quit][enter];
            }
        }
        //离基行的元素
        for(int i=0;i<=m;i++){
            if(i!=enter){
                kernel[quit][i]=kernel[quit][i]/kernel[quit][enter];
            }
        }
        //交叉位置
        kernel[quit][enter]=1.0/kernel[quit][enter];
        
        print();
    } 
}

测试实例

请输入非基本变量的个数与非基本变量的下标
3
2 4 5
请输入基本变量个数与非基本变量的下标
4
1 3 6 7
请输入约束标准型初始单纯形表参数
0 2.5 2.8 76.25
0 1 0 -5
0 0 1 -2
12000 0 0 1
1000 0.1 0.08 0.05

单纯形表
       b       x2      x4      x5      x
c       0       2.5       2.8       76.25
x1      0       1       0       -5
x3      0       0       1       -2
x6      12000       0       0       1
x7      1000       0.1       0.08       0.05
单纯形表
       b       x2      x4      x6      x
c       915000       2.5       2.8       -76.25
x1      60000       1       0       5
x3      24000       0       1       2
x5      12000       0       0       1
x7      400       0.1       0.08       -0.05
单纯形表
       b       x2      x7      x6      x
c       929000       -1       -35       -74.5
x1      60000       1       -0       5
x3      19000       -1.25       -12.5       2.625
x5      12000       0       -0       1
x4      5000       1.25       12.5       -0.625
获得最优解: 929000
单纯形表
       b       x2      x7      x6      x
c       929000       -1       -35       -74.5
x1      60000       1       -0       5
x3      19000       -1.25       -12.5       2.625
x5      12000       0       -0       1
x4      5000       1.25       12.5       -0.625
问题编号 问题名称 问题模型 转化模型 1 飞行员配对方案问题 二分图最大匹配 网络最大 2 太空飞行计划问题 最大权闭合图 网络最小割 3 最小路径覆盖问题 有向无环图最小路径覆盖 网络最大 4 魔术球问题 有向无环图最小路径覆盖 网络最大 5 圆桌问题 二分图多重匹配 网络最大 6 最长递增子序列问题 最多不相交路径 网络最大 7 试题库问题 二分图多重匹配 网络最大 8 机器人路径规划问题 (未解决) 最小费用最大 9 方格取数问题 二分图点权最大独立集 网络最小割 10 餐巾计划问题 线性规划网络优化 最小费用最大 11 航空路线问题 最长不相交路径 最小费用最大 12 软件补丁问题 最小转移代价 最短路径 13 星际转移问题 网络判定 网络最大 14 孤岛营救问题 分层图最短路径 最短路径 15 汽车加油行驶问题 分层图最短路径 最短路径 16 数字梯形问题 最大权不相交路径 最小费用最大 17 运输问题 网络费用量 最小费用最大 18 分配问题 二分图最佳匹配 最小费用最大 19 负载平衡问题 最小代价供求 最小费用最大 20 深海机器人问题 线性规划网络优化 最小费用最大 21 最长k可重区间集问题 最大权不相交路径 最小费用最大 22 最长k可重线段集问题 最大权不相交路径 最小费用最大 23 火星探险问题 线性规划网络优化 最小费用最大 24 骑士共存问题 二分图最大独立集 网络最小割
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高万禄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值