#***************************/
# 線形計画法 */
# coded by Y.Suganuma */
#***************************/
#************/
# クラス LP */
#************/
class LP
#*****************************/
# コンストラクタ */
# n1 : 制約条件の数 */
# m1 : 変数の数 */
# z1 : 目的関数の係数 */
# eq_l : 制約条件の左辺 */
# eq_r : 制約条件の右辺 */
# cp1 : 比較演算子 */
#*****************************/
def initialize(n1, m1, z1, eq_l, eq_r, cp1)
# 初期設定
@_eps = 1.0e-10 # 許容誤差
@_err = 0 # エラーコード (0:正常終了, 1:解無し)
@_n = n1 # 制約条件の数
@_m = m1 # 変数の数
@_a = Array.new(@_n) # 人為変数があるか否か
@_cp = Array.new(@_n) # 比較演算子(-1: 左辺 < 右辺, 0: 左辺 = 右辺, 1: 左辺 > 右辺)
for i1 in 0 ... @_n
@_a[i1] = 0
@_cp[i1] = cp1[i1]
end
@_z = Array.new(@_m) # 目的関数の係数
for i1 in 0 ... @_m
@_z[i1] = z1[i1]
end
# スラック変数と人為変数の数を数える
@_m_s = 0 # スラック変数の数
@_m_a = 0 # 人為変数の数
for i1 in 0 ... @_n
if @_cp[i1] == 0
@_m_a += 1
if eq_r[i1] < 0.0
eq_r[i1] = -eq_r[i1]
for i2 in 0 ... @_m
eq_l[i1][i2] = -eq_l[i1][i2]
end
end
else
@_m_s += 1
if eq_r[i1] < 0.0
@_cp[i1] = -@_cp[i1]
eq_r[i1] = -eq_r[i1]
for i2 in 0 ... @_m
eq_l[i1][i2] = -eq_l[i1][i2]
end
end
if @_cp[i1] > 0
@_m_a += 1
end
end
end
# 単体表の作成
# 初期設定
@_mm = @_m + @_m_s + @_m_a # m + m_s + m_a
@_row = Array.new(@_n) # 各行の基底変数の番号
@_s = Array.new(@_n+1) # 単体表
for i1 in 0 ... @_n+1
@_s[i1] = Array.new(@_mm+1)
if i1 < @_n
@_s[i1][0] = eq_r[i1]
for i2 in 0 ... @_m
@_s[i1][i2+1] = eq_l[i1][i2]
end
for i2 in @_m+1 ... @_mm+1
@_s[i1][i2] = 0.0
end
else
for i2 in 0 ... @_mm+1
@_s[i1][i2] = 0.0
end
end
end
# スラック変数
k = @_m + 1
for i1 in 0 ... @_n
if @_cp[i1] != 0
if @_cp[i1] < 0
@_s[i1][k] = 1.0
@_row[i1] = k - 1
else
@_s[i1][k] = -1.0
end
k += 1
end
end
# 人為変数
for i1 in 0 ... @_n
if @_cp[i1] >= 0
@_s[i1][k] = 1.0
@_row[i1] = k - 1
@_a[i1] = 1
k += 1
end
end
# 目的関数
if @_m_a == 0
for i1 in 0 ... @_m
@_s[@_n][i1+1] = -@_z[i1]
end
else
for i1 in 0 ... @_m+@_m_s+1
for i2 in 0 ... @_n
if @_a[i2] > 0
@_s[@_n][i1] -= @_s[i2][i1]
end
end
end
end
end
#******************************/
# 最適化 */
# sw : =0 : 中間結果無し */
# =1 : 中間結果あり */
# return : =0 : 正常終了 */
# : =1 : 解無し */
#******************************/
def optimize(sw)
# フェーズ1
if sw > 0
if @_m_a > 0
printf("\nphase 1\n")
else
printf("\nphase 2\n")
end
end
opt_run(sw)
# フェーズ2
if @_err == 0 && @_m_a > 0
# 目的関数の変更
@_mm -= @_m_a
for i1 in 0 ... @_mm+1
@_s[@_n][i1] = 0.0
end
for i1 in 0 ... @_n
k = @_row[i1]
if k < @_m
@_s[@_n][0] += @_z[k] * @_s[i1][0]
end
end
for i1 in 0 ... @_mm
for i2 in 0 ... @_n
k = @_row[i2]
if k < @_m
@_s[@_n][i1+1] += @_z[k] * @_s[i2][i1+1]
end
end
if i1 < @_m
@_s[@_n][i1+1] -= @_z[i1]
end
end
# 最適化
if sw > 0
printf("\nphase 2\n")
end
opt_run(sw)
end
return @_err
end
#******************************/
# 最適化(単体表の変形) */
# sw : =0 : 中間結果無し */
# =1 : 中間結果あり */
#******************************/
def opt_run(sw)
@_err = -1
while @_err < 0
# 中間結果
if sw > 0
printf("\n")
output()
end
# 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1
for i1 in 1 ... @_mm+1
if @_s[@_n][i1] < -@_eps
q = i1 - 1
end
if q >= 0
break
end
end
# 終了(最適解)
if q < 0
@_err = 0
# 行の選択( Bland の規則を採用)
else
p = -1
k = -1
min = 0.0
for i1 in 0 ... @_n
if @_s[i1][q+1] > @_eps
x = @_s[i1][0] / @_s[i1][q+1]
if p < 0 || x < min || x == min && @_row[i1] < k
min = x
p = i1
k = @_row[i1]
end
end
end
# 解無し
if p < 0
@_err = 1
# 変形
else
x = @_s[p][q+1]
@_row[p] = q
for i1 in 0 ... @_mm+1
@_s[p][i1] /= x
end
for i1 in 0 ... @_n+1
if i1 != p
x = @_s[i1][q+1]
for i2 in 0 ... @_mm+1
@_s[i1][i2] -= x * @_s[p][i2]
end
end
end
end
end
end
end
#***************/
# 単体表の出力 */
#***************/
def output()
for i1 in 0 ... @_n+1
if i1 < @_n
printf("x%d", @_row[i1]+1)
else
printf(" z")
end
for i2 in 0 ... @_mm+1
printf(" %f", @_s[i1][i2])
end
printf("\n")
end
end
#*************/
# 結果の出力 */
#*************/
def result()
if @_err > 0
printf("\n解が存在しません\n")
else
printf("\n(")
for i1 in 0 ... @_m
x = 0.0
for i2 in 0 ... @_n
if @_row[i2] == i1
x = @_s[i2][0]
break
end
end
if i1 == 0
printf("%f", x)
else
printf(", %f", x)
end
end
printf(") のとき,最大値 %f\n", @_s[@_n][0])
end
end
end
# 入力
# 変数の数と式の数
str = gets();
a = str.split(" ");
m = Integer(a[0]);
n = Integer(a[1]);
cp = Array.new(n)
z = Array.new(m)
eq_r = Array.new(n)
eq_l = Array.new(n)
for i1 in 0 ... n
eq_l[i1] = Array.new(m)
end
# 目的関数の係数
str = gets();
a = str.split(" ");
for i1 in 0 ... m
z[i1] = Float(a[i1])
end
# 制約条件
for i1 in 0 ... n
str = gets();
a = str.split(" ");
for i2 in 0 ... m
eq_l[i1][i2] = Float(a[i2])
end
if a[m] == '<'
cp[i1] = -1
elsif a[m] == '>'
cp[i1] = 1
else
cp[i1] = 0
end
eq_r[i1] = Float(a[m+1])
end
# 実行
lp = LP.new(n, m, z, eq_l, eq_r, cp)
sw = lp.optimize(1)
# 結果の出力
lp.result()