#***************************/ # 線形計画法 */ # 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()