线性规划——单纯型算法

一、线性规划的标准化

(1)目标函数:max

(2)约束条件:等式

(3)变量约束:非负xj >= 0

(4)资源限量:非负bj >= 0

二、非标准型的标准化(以下变量后面括号中均为下标)

(1)min转换为max

min Z = CX  --->    max Z = -CX

(2)不等式转换为等式约束

∑a( i,j )x( j )  <= b( i )   ------>  ∑a( i,j ) x( j ) + x( n+1 ) = b( i )                x( n+1 )为松弛变量

∑a( i,j )x( j )  >= b( i )   ------>  ∑a( i,j ) x( j ) - x( n+1 ) = b( i )                x( n+1 )为松弛变量

(3)变量约束转换

若x( j ) <= 0,x( j ) = - x( j_ ), 则x( j_ ) >= 0;

若x( j )无限制,令x( j_ ) >= 0, x( j__ ) >= 0, 则x( j ) = x( j_ )-x( j__ );

若a <= x( j ) <= b,令x( j_ ) = x( j )-a,则x( j_ )  >= 0,

x( j_ ) <= b-a,这样就变成不等式约束了,即为x( j_ )+x( j__ )  <= b-a,x( j__ )  >= 0。

(4)把b( i )  <= 0转换成b( i ) >= 0

只需要将方程两边乘以一个-1即可。


仔细看会发现所有不等式都是包含等于的,因为线性规划求出最优值并不一定是整数,所以将小于看成小于等于区别不大。


附单纯型算法代码:

#include <bits/stdc++.h>
#define eps 1e-3
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1005;
/*
0:有最优解
1:无界解
2:无解
m1:小于不等式个数
m2:等于等式个数
m3:大于不等式个数
n1:变量和松弛变量的个数
n2:变量、松弛变量、人工变量的个数
*/
class LinearProgram
{
public :
    int n, m, m1, m2, m3, n1, n2;
    int basic[maxn], nonbasic[maxn];
    double a[maxn][maxn];
    void init ( )
    {
        n1 = n+m3;
        n2 = n1+m1;
        for ( int i = 0; i <= n1; i ++ )
            for ( int j = 0; j <= m+1; j ++ )
                a[i][j] = 0.0;
        for ( int i = m1+m2+1, j = m+1; i <= m; i ++, j ++ )
        {
            a[i][j] = -1;       //初始化松弛变量的系数
            a[m+1][j] = -1;
        }
        for ( int i = 1; i <= n1; i ++ )
            nonbasic[i] = i;    //非基本变量(0)
        for ( int i = 1; i <= m; i ++ )
            basic[i] = n1+i;    //基本变量
    }
    void pivot ( int row, int col ) //转轴变换,将等式系数重新计算
    {
        for ( int j = 0; j <= n1; j ++ )
            if ( j != col )
                a[row][j] = a[row][j]/a[row][col];
        a[row][col] = 1.0/a[row][col];
        for ( int i = 0; i <= m+1; i ++ )
        {
            if ( i != row )
            {
                for ( int j = 0; j <= n1; j ++ )
                {
                    if ( j != col )
                    {
                        a[i][j] = a[i][j]-a[i][col]*a[row][j];
                        if ( fabs ( a[i][j] ) < eps )
                            a[i][j] = 0.0;
                    }
                }
                a[i][col] = -a[i][col]*a[row][col];
            }
        }
        swap ( basic[row], nonbasic[col] );
    }
    int selectCol ( int row )
    {
        int res = 0;
        for ( int i = 1; i <= n1; i ++ )
            if ( nonbasic[i] <= n2 && a[row][i] > eps )
            //不在选人工变量,去掉离基变量中的人工变量,如果有解(人工变量置为0)
            {
                res = i;
                break ; //Bland避免循环法则
            }
        return res;
    }
    int selectRow ( int col )
    {
        double tmp = INF;
        int res = 0;
        for ( int i = 1; i <= m; i ++ )
            if ( a[i][col] > eps && tmp > a[i][0]/a[i][col] )
            {
                tmp = a[i][0]/a[i][col];
                res = i;
            }
        return res;
    }
    int select ( int r )
    {
        for ( int col, row; ; )
        {
            col = selectCol ( r );
            if ( col > 0 )
                row = selectRow ( col );
            else
                return 0;
            if ( row > 0 )
                pivot ( row, col );
            else            //第col列全部是负数,则此入基变量可以无限增大
                return 1;   //因为离基变量将再次变正,所以无界解
        }
    }
    int phase1 ( )
    {
        int res = select ( m+1 );
        if ( res > 0 )
            return res;
        for ( int i = 1; i <= m; i ++ )
        {
            if ( basic[i] > n2 )
            {
                if ( a[i][0] > eps )
                    return 2;
                for ( int j = 1; j <= n1; j ++ )
                {
                    if ( fabs ( a[i][j] ) > eps )
                    {
                        pivot ( i, j );
                        break ;
                    }
                }
            }
        }
        return 0;
    }
    int phase2 ( )
    {
        return select ( 0 );
    }
    int compute ( )
    {
        if ( m != m1 )
        {
            int res = phase1 ( );
            if ( res != 0 )
                return res;
        }
        return phase2 ( );
    }
} lp;
double ans[maxn];
void print ( )
{
    memset ( ans, 0, sizeof ( ans ) );
    for ( int i = 1; i <= lp.m; i ++ )
    {
        if ( lp.basic[i] <= lp.n )
            ans[ lp.basic[i] ] = lp.a[i][0];
        printf ( "%d\n", lp.basic[i] );
    }
    for ( int i = 1; i <= lp.n; i ++ )
        printf ( "%.2lf ", ans[i] );
    printf ( "\n" );
}
void solve ( )
{
    char op[15];
    int sign;
    //freopen ( "in2.txt", "r", stdin );
    while ( ~ scanf ( "%d", &lp.n ) )
    {
        scanf ( "%d%d%d", &lp.m1, &lp.m2, &lp.m3 );
        lp.m = lp.m1+lp.m2+lp.m3;
        lp.init ( );
        scanf ( "%s", op );
        if ( strcmp ( "max", op ) == 0 )
            sign = 1;
        else
            sign = -1;
        double x;
        for ( int i = 1; i <= lp.n; i ++ )
        {
            scanf ( "%lf", &x );
            lp.a[0][i] = x*sign;
        }
        scanf ( "%lf", &x );
        lp.a[0][0] = x*sign;
        for ( int i = 1; i <= lp.m; i ++ )
        {
            for ( int j = 1; j <= lp.n; j ++ )
                scanf ( "%lf", &lp.a[i][j] );
            scanf ( "%lf", &lp.a[i][0] );
        }
        for ( int j = 1; j <= lp.n; j ++ )
        {
            x = 0;
            for ( int i = lp.m1+1; i <= lp.m; i ++ )
                x += lp.a[i][j];
            lp.a[lp.m+1][j] = x;
        }
        switch ( lp.compute ( ) )
        {
            case 0 :
                print ( );
            break ;
            case 1 :
                printf ( "无界解\n" );
            break ;
            case 2 :
                printf ( "无解\n" );
        }

    }
}
int main ( )
{
    solve ( );
    return 0;
}
/*
6 0 3 0                     6:变量个数  0:小于  3:等于  0:大于
max 0 -1 3 0 -2 0 0
1 3 -1 0 2 0 7              [x+3x^2-x^3+2x^4 = 7]
0 -2 4 1 0 0 12
0 -4 3 0 8 1 10
ans:0 4 5 0 0 11

4 2 1 1
max 1 1 3 -1 0
1 0 2 0 18
0 2 0 -7 0
1 1 1 1 9
0 1 -1 2 1
ans:0 3.5 4.5 1

4 3 0 0
max 0.75 -20 0.5 -6 0
0.25 -8 -1 9 0
0.5 -12 -0.5 3 0
0 0 1 0 1
ans:1 0 1 0
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值