单纯形算法 matlab 代码实现

单纯形算法思路:

从一个基础可行解开始,迭代搜索下一个基础可行解,直到找到最优解


单纯形算法函数

function [xValue, fValue, iterNum] = simplex_method(A, b, c, isMinValue)
% 输出参数:
% 	xValue : 最优解向量
% 	fValue : 最优解
% 	iterNum : 迭代次数
% 输入参数:
% 	A : 限制条件的系数
% 	b : 限制条件的常数项
% 	c : 目标函数的系数
% 	isMinValue : 目标函数是否是求最小值 0(求最大值) 1(求最小值)	
iterNum = 0;
flag = 0;
xValue = [];
fValue = inf;
if isMinValue == 0
    c = -c; % 如果是求函数最大值,则系数取反
end
[m, n] = size(A);

% 获取基底, 并计算对应的基本解
r = nchoosek(1:n, m);
for ii = 1 : size(r, 1)
    B = A(:, r(ii, :));
    bIdx = r(ii, :);
    if rank(B) == m
        xB = B\b;
        if min(xB(:)) < 0
            flag = 2;
            continue;
        else
            flag = 0;
            break;
        end
    end
end
if flag == 2
    disp('无基本可行解');
    return;
end

x = zeros(n, 1);
x(bIdx) = xB;
while true
    iterNum = iterNum + 1;
    B = A(:, bIdx);
    cB = c(bIdx);
    r = c' - cB' * (B \ A);
    if all(r >= 0)
        xValue = x;
        fValue = c' * x;
        if isMinValue == 0
            fValue = -fValue;
        end
        disp('迭代结束,找到最优解');
        break;
    end
    
    % 计算进基分量下标
    rMin = min(r(:));
    rMinIdx = find(r == rMin);
    
    % 计算迭代方向
    d = zeros(n, 1);
    d(rMinIdx) = 1;
    d(bIdx) = -B\A(:, rMinIdx);
    
    % 计算步长和离基分量下标
    if all(d(bIdx) >= 0)
        disp('当前问题无界, 无最优解');
        break;
    else
        stepVector = -x(bIdx)' ./ d(bIdx);
        step = min(stepVector(d(bIdx) < 0));
        offBaseIdx = bIdx(stepVector == step); % 离基分量下标
    end
    
    bIdx(bIdx == offBaseIdx) = rMinIdx;
%     nIdx(nIdx == rMinIdx) = offBaseIdx;
    x = x + step .* d;
    if iterNum > 100000
        disp('出错,请检查输出参数后重试');
        break;
    end
end
end

测试程序main

A = [1 1 1 -1; -1 2 -4 1];
c = [1 -3 2 1]';
b = [6, 9]';
[x, f, iter] = simplex_method(A, b, c, 1);

总结

花了两个小时,总算写完了,算法思想很简单,代码也不复杂,希望 100 天之后再看能够知道这是个怎么一回事;

你可能感兴趣的:(算法,matlab,开发语言)