本文構建SimplexMax函數,通過構建單純型表和循環迭代,求解線性規劃問題的最優解
clc;clear;
%% 設置變量,調用函數
% 題目參數
A = [0 5 1 0 0;
6 2 0 1 0;
1 1 0 0 1];
b = [15; 24; 5];
c = [2 1 0 0 0];
ind = [3 4 5]
% 無界解
% A = [-2 1 1 0;
% 1 -1 0 1];
% b = [4; 2];
% c = [1 1 0 0];
% ind = [3 4];
% 無窮多最優解
% A = [-1 -1.9 1 0 0 0;
% 1 -1.9 0 1 0 0;
% 1 1.9 0 0 1 0;
% -1 1.9 0 0 0 1];
% b = [-3.8; 3.8; 10.2; 3.8];
% c = [3 5.7 0 0 0 0];
% ind = [3 4 5 6];
[x, z, ST, ca] = SimplexMax(c, A, b, ind) % 調用下述構建的方法進行求解
delete('mysimpleMax.xlsx'); % 刪除原有的Excel表(如果存在的話)
fprintf('正在將單純形表寫入Excel...\n');
writematrix('C1','mysimpleMax.xlsx','Sheet',1,'Range','C1');
writecell({'cB','xB', 'b'},'mysimpleMax.xlsx','Sheet',1,'Range','A2');
[~,n] = size(A);
X = strcat('x', string(1:n));
writematrix(X,'mysimpleMax.xlsx','Sheet',1,'Range','D2');
writematrix(c,'mysimpleMax.xlsx','Sheet',1,'Range','D1');
writematrix(ST,'mysimpleMax.xlsx','Sheet',1,'Range','A3');
fprintf('單純性表寫入完成\n');
%% 構造解單純形法函數
function [x,z,ST,res_case] = SimplexMax(c,A,b,ind_B)
% 單純形法求解標準形線性規劃問題: max cx s.t. Ax=b x>=0
% 輸入參數: c爲目標函數係數, A爲約束方程組係數矩陣, b爲約束方程組常數項, ind_B爲初始基變量索引
% 輸出參數: x最優解, z最優目標函數值, ST存儲單純形表數據,
% res_case=0表示有最優解,res_case=1表示有無界解,res_case=2表示有無窮多解
[m,n] = size(A); % m約束條件個數, n決策變量數
ind_N = setdiff(1:n, ind_B); % 非基變量的索引
ST = [];
format rat
% 循環求解
iteration_round = 0; % 記錄迭代次數
while true
x0 = zeros(n,1);
x0(ind_B) = b; % 初始基可行解
cB = c(ind_B); % 計算cB
Sigma = zeros(1,n); % 創建Sigma存儲檢驗數並初始化爲0
Sigma(ind_N) = c(ind_N) - cB*A(:,ind_N); % 計算並存入(非基變量)檢驗數
[~, k] = max(Sigma); % 選出最大檢驗數, 確定進基變量索引k (注:[a,b]=max(c)中,a爲c中的最大值,b爲c中最大值的index)
% fprintf('確定進基變量索引:%d\n',k)
Theta = b ./ A(:,k); % 計算θ(取A的k列,使b./(A的k列))
Theta(Theta == 1/0) = NaN;
Theta(Theta <= 0) = NaN;
% Theta(Theta<=0) = 10000;
% [~, q] = min(Theta); % 選出最小θ
[~, q] = min(Theta); % 選出最小正數θ
el = ind_B(q); % 確定出基變量索引el, 主元爲A(q,k)
% fprintf('確定出基變量索引:%d\n',el)
vals = [cB',ind_B',b,A,Theta]; % 存儲單純形表
vals = [vals; NaN, NaN, NaN, Sigma, NaN]; % 存儲單純性表Sigma列
[~,vals_width] = size(vals); % 創建一個與vals等寬的空矩陣
vals = [vals; [1:vals_width]* NaN]; % 將該行添加到vals最後作爲分隔
ST = [ST; vals]; % 將上述構建的單純性表vals添加到ST矩陣中
if ~any(Sigma > 0) % 若不存在任何Sigma>0,此基可行解爲最優解
fprintf('得到最優解');
x = x0;
z = c * x;
res_case = 0;
return
end
if all(A(:,k) <= 0) %有無界解
fprintf('有無界解');
x = [];
z = NaN;
res_case = 1;
break
end
if ~any(Sigma(ind_B)>0) && any(Sigma(ind_N)==0) % 有無窮多最優解
fprintf('有無窮多最優解')
x = x0;
z = c * x;
res_case = 2;
break
end
iteration_round = iteration_round + 1;
fprintf('迭代第%d次\n',iteration_round)
fprintf('確定進基變量索引:%d 出基變量索引: %d\n',k,el)
% 換基
ind_B(ind_B == el) = k; %新的基變量索引
ind_N = setdiff(1:n, ind_B); %非基變量索引(選取了ind_B和[1:n]的差集)
% 更新A和b
A(:,ind_N) = A(:,ind_B) \ A(:,ind_N); % Q1 = inv(A(:,ind_B))
b = A(:,ind_B) \ b; % b2 = inv(Q1) * b1
A(:,ind_B) = eye(m,m);
end
end
注意:本文采用的對單純性表進行操作的方法並不是改進單純型法,如果需要使用改進單純型法進行求解請參考其他文章,並對下述操作進行改進
% 換基
ind_B(ind_B == el) = k; %新的基變量索引
ind_N = setdiff(1:n, ind_B); %非基變量索引(選取了ind_B和[1:n]的差集)