| 情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/
/* 線形計画法 */
/* coded by Y.Suganuma */
/****************************/
#include <stdio.h>
/*************/
/* クラス LP */
/*************/
class LP
{
int n; // 制約条件の数
int m; // 変数の数
int m_s; // スラック変数の数
int m_a; // 人為変数の数
int mm; // m + m_s + m_a
int *a; // 人為変数があるか否か
int *cp; // 比較演算子(-1: 左辺 < 右辺, 0: 左辺 = 右辺, 1: 左辺 > 右辺)
int *row; // 各行の基底変数の番号
double *z; // 目的関数の係数
double **s; // 単体表
double eps; // 許容誤差
int err; // エラーコード (0:正常終了, 1:解無し)
public:
/******************************/
/* コンストラクタ */
/* n1 : 制約条件の数 */
/* m1 : 変数の数 */
/* z1 : 目的関数の係数 */
/* eq_l : 制約条件の左辺 */
/* eq_r : 制約条件の右辺 */
/* cp1 : 比較演算子 */
/******************************/
LP(int n1, int m1, double *z1, double **eq_l, double *eq_r, int *cp1)
{
int i1, i2, k;
// 初期設定
eps = 1.0e-10;
err = 0;
n = n1;
m = m1;
a = new int [n];
cp = new int [n];
for (i1 = 0; i1 < n; i1++) {
a[i1] = 0;
cp[i1] = cp1[i1];
}
z = new double [m];
for (i1 = 0; i1 < m; i1++)
z[i1] = z1[i1];
// スラック変数と人為変数の数を数える
m_s = 0;
m_a = 0;
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] == 0) {
m_a++;
if (eq_r[i1] < 0.0) {
eq_r[i1] = -eq_r[i1];
for (i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
}
else {
m_s++;
if (eq_r[i1] < 0.0) {
cp[i1] = -cp[i1];
eq_r[i1] = -eq_r[i1];
for (i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
if (cp[i1] > 0)
m_a++;
}
}
// 単体表の作成
// 初期設定
mm = m + m_s + m_a;
row = new int [n];
s = new double * [n+1];
for (i1 = 0; i1 <= n; i1++) {
s[i1] = new double [mm+1];
if (i1 < n) {
s[i1][0] = eq_r[i1];
for (i2 = 0; i2 < m; i2++)
s[i1][i2+1] = eq_l[i1][i2];
for (i2 = m+1; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
else {
for (i2 = 0; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
}
// スラック変数
k = m + 1;
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] != 0) {
if (cp[i1] < 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
}
else
s[i1][k] = -1.0;
k++;
}
}
// 人為変数
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] >= 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
a[i1] = 1;
k++;
}
}
// 目的関数
if (m_a == 0) {
for (i1 = 0; i1 < m; i1++)
s[n][i1+1] = -z[i1];
}
else {
for (i1 = 0; i1 <= m+m_s; i1++) {
for (i2 = 0; i2 < n; i2++) {
if (a[i2] > 0)
s[n][i1] -= s[i2][i1];
}
}
}
}
/*******************************/
/* 最適化 */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/* return : =0 : 正常終了 */
/* : =1 : 解無し */
/*******************************/
int optimize(int sw)
{
int i1, i2, k;
// フェーズ1
if (sw > 0) {
if (m_a > 0)
printf("\nphase 1\n");
else
printf("\nphase 2\n");
}
opt_run(sw);
// フェーズ2
if (err == 0 && m_a > 0) {
// 目的関数の変更
mm -= m_a;
for (i1 = 0; i1 <= mm; i1++)
s[n][i1] = 0.0;
for (i1 = 0; i1 < n; i1++) {
k = row[i1];
if (k < m)
s[n][0] += z[k] * s[i1][0];
}
for (i1 = 0; i1 < mm; i1++) {
for (i2 = 0; i2 < n; i2++) {
k = row[i2];
if (k < m)
s[n][i1+1] += z[k] * s[i2][i1+1];
}
if (i1 < m)
s[n][i1+1] -= z[i1];
}
// 最適化
if (sw > 0)
printf("\nphase 2\n");
opt_run(sw);
}
return err;
}
/*******************************/
/* 最適化(単体表の変形) */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/*******************************/
void opt_run(int sw)
{
int i1, i2, p, q, k;
double x, min;
err = -1;
while (err < 0) {
// 中間結果
if (sw > 0) {
printf("\n");
output();
}
// 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1;
for (i1 = 1; i1 <= mm && q < 0; i1++) {
if (s[n][i1] < -eps)
q = i1 - 1;
}
// 終了(最適解)
if (q < 0)
err = 0;
// 行の選択( Bland の規則を採用)
else {
p = -1;
k = -1;
min = 0.0;
for (i1 = 0; i1 < n; i1++) {
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];
}
}
}
// 解無し
if (p < 0)
err = 1;
// 変形
else {
x = s[p][q+1];
row[p] = q;
for (i1 = 0; i1 <= mm; i1++)
s[p][i1] /= x;
for (i1 = 0; i1 <= n; i1++) {
if (i1 != p) {
x = s[i1][q+1];
for (i2 = 0; i2 <= mm; i2++)
s[i1][i2] -= x * s[p][i2];
}
}
}
}
}
}
/****************/
/* 単体表の出力 */
/****************/
void output()
{
int i1, i2;
for (i1 = 0; i1 <= n; i1++) {
if (i1 < n)
printf("x%d", row[i1]+1);
else
printf(" z");
for (i2 = 0; i2 <= mm; i2++)
printf(" %f", s[i1][i2]);
printf("\n");
}
}
/**************/
/* 結果の出力 */
/**************/
void result()
{
double x;
int i1, i2;
if (err > 0)
printf("\n解が存在しません\n");
else {
printf("\n(");
for (i1 = 0; i1 < m; i1++) {
x = 0.0;
for (i2 = 0; i2 < n; i2++) {
if (row[i2] == i1) {
x = s[i2][0];
break;
}
}
if (i1 == 0)
printf("%f", x);
else
printf(", %f", x);
}
printf(") のとき,最大値 %f\n", s[n][0]);
}
}
};
/****************/
/* main program */
/****************/
int main()
{
double **eq_l, *eq_r, *z;
int i1, i2, n, m, *cp, sw;
char c[2];
// 入力
// 変数の数と式の数
scanf("%d %d", &m, &n);
cp = new int [n];
z = new double [m];
eq_l = new double * [n];
eq_r = new double [n];
for (i1 = 0; i1 < n; i1++)
eq_l[i1] = new double [m];
// 目的関数の係数
for (i1 = 0; i1 < m; i1++)
scanf("%lf", &z[i1]);
// 制約条件
for (i1 = 0; i1 < n; i1++) {
for (i2 = 0; i2 < m; i2++)
scanf("%lf", &eq_l[i1][i2]);
scanf("%s", c);
if (c[0] == '<')
cp[i1] = -1;
else if (c[0] == '>')
cp[i1] = 1;
else
cp[i1] = 0;
scanf("%lf", &eq_r[i1]);
}
// 実行
LP lp = LP(n, m, z, eq_l, eq_r, cp);
sw = lp.optimize(1);
// 結果の出力
lp.result();
return 0;
}
/****************************/
/* 線形計画法 */
/* coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.StringTokenizer;
/*************/
/* クラス LP */
/*************/
class LP
{
private int n; // 制約条件の数
private int m; // 変数の数
private int m_s; // スラック変数の数
private int m_a; // 人為変数の数
private int mm; // m + m_s + m_a
private int a[]; // 人為変数があるか否か
private int cp[]; // 比較演算子(-1:左辺<右辺, 0:左辺=右辺, 1:左辺>右辺)
private int row[]; // 各行の基底変数の番号
private double z[]; // 目的関数の係数
private double s[][]; // 単体表
private double eps; // 許容誤差
private int err; // エラーコード (0:正常終了, 1:解無し)
/******************************/
/* コンストラクタ */
/* n1 : 制約条件の数 */
/* m1 : 変数の数 */
/* z1 : 目的関数の係数 */
/* eq_l : 制約条件の左辺 */
/* eq_r : 制約条件の右辺 */
/* cp1 : 比較演算子 */
/******************************/
LP(int n1, int m1, double z1[], double eq_l[][], double eq_r[], int cp1[])
{
int i1, i2, k;
// 初期設定
eps = 1.0e-10;
err = 0;
n = n1;
m = m1;
a = new int [n];
cp = new int [n];
for (i1 = 0; i1 < n; i1++) {
a[i1] = 0;
cp[i1] = cp1[i1];
}
z = new double [m];
for (i1 = 0; i1 < m; i1++)
z[i1] = z1[i1];
// スラック変数と人為変数の数を数える
m_s = 0;
m_a = 0;
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] == 0) {
m_a++;
if (eq_r[i1] < 0.0) {
eq_r[i1] = -eq_r[i1];
for (i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
}
else {
m_s++;
if (eq_r[i1] < 0.0) {
cp[i1] = -cp[i1];
eq_r[i1] = -eq_r[i1];
for (i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
if (cp[i1] > 0)
m_a++;
}
}
// 単体表の作成
// 初期設定
mm = m + m_s + m_a;
row = new int [n];
s = new double [n+1][mm+1];
for (i1 = 0; i1 <= n; i1++) {
if (i1 < n) {
s[i1][0] = eq_r[i1];
for (i2 = 0; i2 < m; i2++)
s[i1][i2+1] = eq_l[i1][i2];
for (i2 = m+1; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
else {
for (i2 = 0; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
}
// スラック変数
k = m + 1;
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] != 0) {
if (cp[i1] < 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
}
else
s[i1][k] = -1.0;
k++;
}
}
// 人為変数
for (i1 = 0; i1 < n; i1++) {
if (cp[i1] >= 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
a[i1] = 1;
k++;
}
}
// 目的関数
if (m_a == 0) {
for (i1 = 0; i1 < m; i1++)
s[n][i1+1] = -z[i1];
}
else {
for (i1 = 0; i1 <= m+m_s; i1++) {
for (i2 = 0; i2 < n; i2++) {
if (a[i2] > 0)
s[n][i1] -= s[i2][i1];
}
}
}
}
/*******************************/
/* 最適化 */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/* return : =0 : 正常終了 */
/* : =1 : 解無し */
/*******************************/
int optimize(int sw)
{
int i1, i2, k;
// フェーズ1
if (sw > 0) {
if (m_a > 0)
System.out.printf("\nphase 1\n");
else
System.out.printf("\nphase 2\n");
}
opt_run(sw);
// フェーズ2
if (err == 0 && m_a > 0) {
// 目的関数の変更
mm -= m_a;
for (i1 = 0; i1 <= mm; i1++)
s[n][i1] = 0.0;
for (i1 = 0; i1 < n; i1++) {
k = row[i1];
if (k < m)
s[n][0] += z[k] * s[i1][0];
}
for (i1 = 0; i1 < mm; i1++) {
for (i2 = 0; i2 < n; i2++) {
k = row[i2];
if (k < m)
s[n][i1+1] += z[k] * s[i2][i1+1];
}
if (i1 < m)
s[n][i1+1] -= z[i1];
}
// 最適化
if (sw > 0)
System.out.printf("\nphase 2\n");
opt_run(sw);
}
return err;
}
/*******************************/
/* 最適化(単体表の変形) */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/*******************************/
void opt_run(int sw)
{
int i1, i2, p, q, k;
double x, min;
err = -1;
while (err < 0) {
// 中間結果
if (sw > 0) {
System.out.printf("\n");
output();
}
// 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1;
for (i1 = 1; i1 <= mm && q < 0; i1++) {
if (s[n][i1] < -eps)
q = i1 - 1;
}
// 終了(最適解)
if (q < 0)
err = 0;
// 行の選択( Bland の規則を採用)
else {
p = -1;
k = -1;
min = 0.0;
for (i1 = 0; i1 < n; i1++) {
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];
}
}
}
// 解無し
if (p < 0)
err = 1;
// 変形
else {
x = s[p][q+1];
row[p] = q;
for (i1 = 0; i1 <= mm; i1++)
s[p][i1] /= x;
for (i1 = 0; i1 <= n; i1++) {
if (i1 != p) {
x = s[i1][q+1];
for (i2 = 0; i2 <= mm; i2++)
s[i1][i2] -= x * s[p][i2];
}
}
}
}
}
}
/****************/
/* 単体表の出力 */
/****************/
void output()
{
int i1, i2;
for (i1 = 0; i1 <= n; i1++) {
if (i1 < n)
System.out.printf("x%d", row[i1]+1);
else
System.out.printf(" z");
for (i2 = 0; i2 <= mm; i2++)
System.out.printf(" %f", s[i1][i2]);
System.out.printf("\n");
}
}
/**************/
/* 結果の出力 */
/**************/
void result()
{
double x;
int i1, i2;
if (err > 0)
System.out.printf("\n解が存在しません\n");
else {
System.out.printf("\n(");
for (i1 = 0; i1 < m; i1++) {
x = 0.0;
for (i2 = 0; i2 < n; i2++) {
if (row[i2] == i1) {
x = s[i2][0];
break;
}
}
if (i1 == 0)
System.out.printf("%f", x);
else
System.out.printf(", %f", x);
}
System.out.printf(") のとき,最大値 %f\n", s[n][0]);
}
}
}
/****************/
/* main program */
/****************/
public class Test
{
public static void main (String[] args) throws IOException
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
double eq_l[][], eq_r[], z[];
int i1, i2, n, m, cp[], sw;
String c;
StringTokenizer str;
// 入力
// 変数の数と式の数
str = new StringTokenizer(in.readLine(), " ");
m = Integer.parseInt(str.nextToken());
n = Integer.parseInt(str.nextToken());
cp = new int [n];
z = new double [m];
eq_l = new double [n][m];
eq_r = new double [n];
// 目的関数の係数
str = new StringTokenizer(in.readLine(), " ");
for (i1 = 0; i1 < m; i1++)
z[i1] = Double.parseDouble(str.nextToken());
// 制約条件
for (i1 = 0; i1 < n; i1++) {
str = new StringTokenizer(in.readLine(), " ");
for (i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = Double.parseDouble(str.nextToken());
c = str.nextToken();
if (c.compareTo("<") == 0)
cp[i1] = -1;
else if (c.compareTo(">") == 0)
cp[i1] = 1;
else
cp[i1] = 0;
eq_r[i1] = Double.parseDouble(str.nextToken());
}
// 実行
LP lp = new LP(n, m, z, eq_l, eq_r, cp);
sw = lp.optimize(1);
// 結果の出力
lp.result();
}
}
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>最適化(線形計画法)</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<SCRIPT TYPE="text/javascript">
lp = null; // オブジェクト LP
/****************/
/* main program */
/****************/
function main()
{
// 入力
// 変数の数と式の数
let m = parseInt(document.getElementById("order").value);
let n = parseInt(document.getElementById("cond").value);
let cp = new Array(n);
let z = new Array(m);
let eq_l = new Array(n);
for (let i1 = 0; i1 < n; i1++)
eq_l[i1] = new Array(m);
let eq_r = new Array(n);
// 目的関数の係数
let s1 = (document.getElementById("data").value).split("\n");
let s2 = s1[0].split(" ");
for (let i1 = 0; i1 < m; i1++)
z[i1] = parseFloat(s2[i1]);
// 制約条件
for (let i1 = 0; i1 < n; i1++) {
s2 = s1[i1+1].split(" ");
for (let i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = parseFloat(s2[i2]);
c = s2[m];
if (c == "<")
cp[i1] = -1;
else if (c == ">")
cp[i1] = 1;
else
cp[i1] = 0;
eq_r[i1] = parseFloat(s2[m+1]);
}
// 実行
lp = new LP(n, m, z, eq_l, eq_r, cp);
sw = lp.optimize(1);
// 結果の出力
lp.result();
document.getElementById("ans").value = lp.str;
}
/******************************/
/* オブジェクト LP */
/* n1 : 制約条件の数 */
/* m1 : 変数の数 */
/* z1 : 目的関数の係数 */
/* eq_l : 制約条件の左辺 */
/* eq_r : 制約条件の右辺 */
/* cp1 : 比較演算子 */
/******************************/
function LP(n1, m1, z1, eq_l, eq_r, cp1)
{
// 初期設定
this.str = ""; // 出力文字列
this.eps = 1.0e-10; // 許容誤差
this.err = 0; // エラーコード (0:正常終了, 1:解無し)
this.n = n1; // 制約条件の数
this.m = m1; // 変数の数
this.a = new Array(this.n); // 人為変数があるか否か
this.cp = new Array(this.n); // 比較演算子(-1: 左辺 < 右辺, 0:左辺 = 右辺, 1:左辺 > 右辺)
for (let i1 = 0; i1 < this.n; i1++) {
this.a[i1] = 0;
this.cp[i1] = cp1[i1];
}
this.z = new Array(this.m); // 目的関数の係数
for (let i1 = 0; i1 < this.m; i1++)
this.z[i1] = z1[i1];
// スラック変数と人為変数の数を数える
this.m_s = 0; // スラック変数の数
this.m_a = 0; // 人為変数の数
for (let i1 = 0; i1 < this.n; i1++) {
if (this.cp[i1] == 0) {
this.m_a++;
if (eq_r[i1] < 0.0) {
eq_r[i1] = -eq_r[i1];
for (let i2 = 0; i2 < this.m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
}
else {
this.m_s++;
if (eq_r[i1] < 0.0) {
this.cp[i1] = -this.cp[i1];
eq_r[i1] = -eq_r[i1];
for (let i2 = 0; i2 < this.m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
if (this.cp[i1] > 0)
this.m_a++;
}
}
// 単体表の作成
// 初期設定
this.mm = this.m + this.m_s + this.m_a; // m + m_s + m_a
this.row = new Array(this.n); // 各行の基底変数の番号
this.s = new Array(this.n+1); // 単体表
for (let i1 = 0; i1 <= this.n; i1++) {
this.s[i1] = new Array(this.mm+1);
if (i1 < this.n) {
this.s[i1][0] = eq_r[i1];
for (let i2 = 0; i2 < this.m; i2++)
this.s[i1][i2+1] = eq_l[i1][i2];
for (let i2 = this.m+1; i2 <= this.mm; i2++)
this.s[i1][i2] = 0.0;
}
else {
for (let i2 = 0; i2 <= this.mm; i2++)
this.s[i1][i2] = 0.0;
}
}
// スラック変数
let k = this.m + 1;
for (let i1 = 0; i1 < this.n; i1++) {
if (this.cp[i1] != 0) {
if (this.cp[i1] < 0) {
this.s[i1][k] = 1.0;
this.row[i1] = k - 1;
}
else
this.s[i1][k] = -1.0;
k++;
}
}
// 人為変数
for (let i1 = 0; i1 < this.n; i1++) {
if (this.cp[i1] >= 0) {
this.s[i1][k] = 1.0;
this.row[i1] = k - 1;
this.a[i1] = 1;
k++;
}
}
// 目的関数
if (this.m_a == 0) {
for (let i1 = 0; i1 < this.m; i1++)
this.s[this.n][i1+1] = -this.z[i1];
}
else {
for (let i1 = 0; i1 <= this.m+this.m_s; i1++) {
for (let i2 = 0; i2 < this.n; i2++) {
if (this.a[i2] > 0)
this.s[this.n][i1] -= this.s[i2][i1];
}
}
}
}
/*******************************/
/* 最適化 */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/* return : =0 : 正常終了 */
/* : =1 : 解無し */
/*******************************/
LP.prototype.optimize = function(sw)
{
// フェーズ1
if (sw > 0) {
if (lp.m_a > 0)
lp.str += "\nphase 1\n";
else
lp.str += "\nphase 2\n";
}
lp.opt_run(sw);
// フェーズ2
if (lp.err == 0 && lp.m_a > 0) {
// 目的関数の変更
lp.mm -= lp.m_a;
for (let i1 = 0; i1 <= lp.mm; i1++)
lp.s[lp.n][i1] = 0.0;
for (let i1 = 0; i1 < lp.n; i1++) {
let k = lp.row[i1];
if (k < lp.m)
lp.s[lp.n][0] += lp.z[k] * lp.s[i1][0];
}
for (let i1 = 0; i1 < lp.mm; i1++) {
for (i2 = 0; i2 < lp.n; i2++) {
let k = lp.row[i2];
if (k < lp.m)
lp.s[lp.n][i1+1] += lp.z[k] * lp.s[i2][i1+1];
}
if (i1 < lp.m)
lp.s[lp.n][i1+1] -= lp.z[i1];
}
// 最適化
if (sw > 0)
lp.str += "\nphase 2\n";
lp.opt_run(sw);
}
return lp.err;
}
/*******************************/
/* 最適化(単体表の変形) */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/*******************************/
LP.prototype.opt_run = function(sw)
{
lp.err = -1;
while (lp.err < 0) {
// 中間結果
if (sw > 0) {
lp.str += "\n";
lp.output();
}
// 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
let q = -1;
for (let i1 = 1; i1 <= lp.mm && q < 0; i1++) {
if (lp.s[lp.n][i1] < -lp.eps)
q = i1 - 1;
}
// 終了(最適解)
if (q < 0)
lp.err = 0;
// 行の選択( Bland の規則を採用)
else {
let p = -1;
let k = -1;
let min = 0.0;
for (let i1 = 0; i1 < lp.n; i1++) {
if (lp.s[i1][q+1] > lp.eps) {
let x = lp.s[i1][0] / lp.s[i1][q+1];
if (p < 0 || x < min || x == min && lp.row[i1] < k) {
min = x;
p = i1;
k = lp.row[i1];
}
}
}
// 解無し
if (p < 0)
lp.err = 1;
// 変形
else {
let x = lp.s[p][q+1];
lp.row[p] = q;
for (let i1 = 0; i1 <= lp.mm; i1++)
lp.s[p][i1] /= x;
for (let i1 = 0; i1 <= lp.n; i1++) {
if (i1 != p) {
x = lp.s[i1][q+1];
for (let i2 = 0; i2 <= lp.mm; i2++)
lp.s[i1][i2] -= x * lp.s[p][i2];
}
}
}
}
}
}
/****************/
/* 単体表の出力 */
/****************/
LP.prototype.output = function()
{
for (let i1 = 0; i1 <= lp.n; i1++) {
if (i1 < lp.n)
lp.str += ("x" + (lp.row[i1]+1));
else
lp.str += " z";
for (let i2 = 0; i2 <= lp.mm; i2++)
lp.str += (" " + lp.s[i1][i2]);
lp.str += "\n";
}
}
/**************/
/* 結果の出力 */
/**************/
LP.prototype.result = function()
{
if (lp.err > 0)
lp.str += "\n解が存在しません\n";
else {
lp.str += "\n(";
for (let i1 = 0; i1 < lp.m; i1++) {
let x = 0.0;
for (let i2 = 0; i2 < lp.n; i2++) {
if (lp.row[i2] == i1) {
x = lp.s[i2][0];
break;
}
}
if (i1 == 0)
lp.str += x;
else
lp.str += (", " + x);
}
lp.str += (") のとき,最大値 " + lp.s[lp.n][0] + "\n");
}
}
</SCRIPT>
</HEAD>
<BODY STYLE="font-size: 130%; background-color: #eeffee;">
<H2 STYLE="text-align:center"><B>最適化(線形計画法)</B></H2>
<DL>
<DT> テキストフィールドおよびテキストエリアには,例として,
<DD><DL>
<DT>目的関数,
<DD>z = 3x<SUB>1</SUB> + 2x<SUB>2</SUB> (1)
<DT>を,制約条件,
<DD>3x<SUB>1</SUB> + x<SUB>2</SUB> ≦ 9 (2)
<DD>2.5x<SUB>1</SUB> + 2x<SUB>2</SUB> ≦ 12.5 (3)
<DD>x<SUB>1</SUB> + 2x<SUB>2</SUB> ≦ 8 (4)
<DD>x<SUB>1</SUB>, x<SUB>2</SUB> ≧ 0
<DT>のもとで,最大にする.
</DL></DD>
<DT>を実行するための値が設定されています.他の問題を実行する場合は,それらを適切に修正してください.
</DL>
<DIV STYLE="text-align:center">
変数の数:<INPUT ID="order" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="2">
制約条件数:<INPUT ID="cond" STYLE="font-size: 100%;" TYPE="text" SIZE="3" VALUE="3">
<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">OK</BUTTON><BR><BR>
入力データ:<TEXTAREA ID="data" COLS="30" ROWS="15" STYLE="font-size: 100%">
3 2
3 1 < 9
2.5 2 < 12.5
1 2 < 8</TEXTAREA><BR><BR>
<TEXTAREA ID="ans" COLS="60" ROWS="15" STYLE="font-size: 100%"></TEXTAREA>
</DIV>
</BODY>
</HTML>
<?php /****************************/ /* 線形計画法 */ /* coded by Y.Suganuma */ /****************************/ #include/*************/ /* クラス LP */ /*************/ class LP { private $n; // 制約条件の数 private $m; // 変数の数 private $m_s; // スラック変数の数 private $m_a; // 人為変数の数 private $mm; // m + m_s + m_a private $a = array(); // 人為変数があるか否か private $cp = array(); // 比較演算子(-1: 左辺 < 右辺, 0: 左辺 = 右辺, 1: 左辺 > 右辺) private $row = array(); // 各行の基底変数の番号 private $z = array(); // 目的関数の係数 private $s = array(); // 単体表 private $eps; // 許容誤差 private $err; // エラーコード (0:正常終了, 1:解無し) /******************************/ /* コンストラクタ */ /* n1 : 制約条件の数 */ /* m1 : 変数の数 */ /* z1 : 目的関数の係数 */ /* eq_l : 制約条件の左辺 */ /* eq_r : 制約条件の右辺 */ /* cp1 : 比較演算子 */ /******************************/ function LP($n1, $m1, $z1, $eq_l, $eq_r, $cp1) { // 初期設定 $this->eps = 1.0e-10; $this->err = 0; $this->n = $n1; $this->m = $m1; for ($i1 = 0; $i1 < $this->n; $i1++) { $this->a[$i1] = 0; $this->cp[$i1] = $cp1[$i1]; } for ($i1 = 0; $i1 < $this->m; $i1++) $this->z[$i1] = $z1[$i1]; // スラック変数と人為変数の数を数える $this->m_s = 0; $this->m_a = 0; for ($i1 = 0; $i1 < $this->n; $i1++) { if ($this->cp[$i1] == 0) { $this->m_a++; if ($eq_r[$i1] < 0.0) { $eq_r[$i1] = -$eq_r[$i1]; for ($i2 = 0; $i2 < $this->m; $i2++) $eq_l[$i1][$i2] = -$eq_l[$i1][$i2]; } } else { $this->m_s++; if ($eq_r[$i1] < 0.0) { $this->cp[$i1] = -$this->cp[$i1]; $eq_r[$i1] = -$eq_r[$i1]; for ($i2 = 0; $i2 < $this->m; $i2++) $eq_l[$i1][$i2] = -$eq_l[$i1][$i2]; } if ($this->cp[$i1] > 0) $this->m_a++; } } // 単体表の作成 // 初期設定 $this->mm = $this->m + $this->m_s + $this->m_a; for ($i1 = 0; $i1 <= $this->n; $i1++) { $this->s[$i1] = array($this->mm+1); if ($i1 < $this->n) { $this->s[$i1][0] = $eq_r[$i1]; for ($i2 = 0; $i2 < $this->m; $i2++) $this->s[$i1][$i2+1] = $eq_l[$i1][$i2]; for ($i2 = $this->m+1; $i2 <= $this->mm; $i2++) $this->s[$i1][$i2] = 0.0; } else { for ($i2 = 0; $i2 <= $this->mm; $i2++) $this->s[$i1][$i2] = 0.0; } } // スラック変数 $k = $this->m + 1; for ($i1 = 0; $i1 < $this->n; $i1++) { if ($this->cp[$i1] != 0) { if ($this->cp[$i1] < 0) { $this->s[$i1][$k] = 1.0; $this->row[$i1] = $k - 1; } else $this->s[$i1][$k] = -1.0; $k++; } } // 人為変数 for ($i1 = 0; $i1 < $this->n; $i1++) { if ($this->cp[$i1] >= 0) { $this->s[$i1][$k] = 1.0; $this->row[$i1] = $k - 1; $this->a[$i1] = 1; $k++; } } // 目的関数 if ($this->m_a == 0) { for ($i1 = 0; $i1 < $this->m; $i1++) $this->s[$this->n][$i1+1] = -$this->z[$i1]; } else { for ($i1 = 0; $i1 <= $this->m+$this->m_s; $i1++) { for ($i2 = 0; $i2 < $this->n; $i2++) { if ($this->a[$i2] > 0) $this->s[$this->n][$i1] -= $this->s[$i2][$i1]; } } } } /*******************************/ /* 最適化 */ /* sw : =0 : 中間結果無し */ /* =1 : 中間結果あり */ /* return : =0 : 正常終了 */ /* : =1 : 解無し */ /*******************************/ function optimize($sw) { // フェーズ1 if ($sw > 0) { if ($this->m_a > 0) printf("\nphase 1\n"); else printf("\nphase 2\n"); } $this->opt_run($sw); // フェーズ2 if ($this->err == 0 && $this->m_a > 0) { // 目的関数の変更 $this->mm -= $this->m_a; for ($i1 = 0; $i1 <= $this->mm; $i1++) $this->s[$this->n][$i1] = 0.0; for ($i1 = 0; $i1 < $this->n; $i1++) { $k = $this->row[$i1]; if ($k < $this->m) $this->s[$this->n][0] += $this->z[$k] * $this->s[$i1][0]; } for ($i1 = 0; $i1 < $this->mm; $i1++) { for ($i2 = 0; $i2 < $this->n; $i2++) { $k = $this->row[$i2]; if ($k < $this->m) $this->s[$this->n][$i1+1] += $this->z[$k] * $this->s[$i2][$i1+1]; } if ($i1 < $this->m) $this->s[$this->n][$i1+1] -= $this->z[$i1]; } // 最適化 if ($sw > 0) printf("\nphase 2\n"); $this->opt_run($sw); } return $this->err; } /*******************************/ /* 最適化(単体表の変形) */ /* sw : =0 : 中間結果無し */ /* =1 : 中間結果あり */ /*******************************/ function opt_run($sw) { $this->err = -1; while ($this->err < 0) { // 中間結果 if ($sw > 0) { printf("\n"); $this->output(); } // 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則) $q = -1; for ($i1 = 1; $i1 <= $this->mm && $q < 0; $i1++) { if ($this->s[$this->n][$i1] < -$this->eps) $q = $i1 - 1; } // 終了(最適解) if ($q < 0) $this->err = 0; // 行の選択( Bland の規則を採用) else { $p = -1; $k = -1; $min = 0.0; for ($i1 = 0; $i1 < $this->n; $i1++) { if ($this->s[$i1][$q+1] > $this->eps) { $x = $this->s[$i1][0] / $this->s[$i1][$q+1]; if ($p < 0 || $x < $min || $x == $min && $this->row[$i1] < $k) { $min = $x; $p = $i1; $k = $this->row[$i1]; } } } // 解無し if ($p < 0) $this->err = 1; // 変形 else { $x = $this->s[$p][$q+1]; $this->row[$p] = $q; for ($i1 = 0; $i1 <= $this->mm; $i1++) $this->s[$p][$i1] /= $x; for ($i1 = 0; $i1 <= $this->n; $i1++) { if ($i1 != $p) { $x = $this->s[$i1][$q+1]; for ($i2 = 0; $i2 <= $this->mm; $i2++) $this->s[$i1][$i2] -= $x * $this->s[$p][$i2]; } } } } } } /****************/ /* 単体表の出力 */ /****************/ function output() { for ($i1 = 0; $i1 <= $this->n; $i1++) { if ($i1 < $this->n) printf("x%d", $this->row[$i1]+1); else printf(" z"); for ($i2 = 0; $i2 <= $this->mm; $i2++) printf(" %f", $this->s[$i1][$i2]); printf("\n"); } } /**************/ /* 結果の出力 */ /**************/ function result() { if ($this->err > 0) printf("\n解が存在しません\n"); else { printf("\n("); for ($i1 = 0; $i1 < $this->m; $i1++) { $x = 0.0; for ($i2 = 0; $i2 < $this->n; $i2++) { if ($this->row[$i2] == $i1) { $x = $this->s[$i2][0]; break; } } if ($i1 == 0) printf("%f", $x); else printf(", %f", $x); } printf(") のとき,最大値 %f\n", $this->s[$this->n][0]); } } } // 入力 // 変数の数と式の数 fscanf(STDIN, "%d %d", $m, $n); $cp = array($n); $z = array($m); $eq_l = array($n); $eq_r = array($n); for ($i1 = 0; $i1 < $n; $i1++) $eq_l[$i1] = array($m); // 目的関数の係数 $str = trim(fgets(STDIN)); $z[0] = floatval(strtok($str, " ")); for ($i1 = 1; $i1 < $m; $i1++) $z[$i1] = floatval(strtok(" ")); // 制約条件 for ($i1 = 0; $i1 < $n; $i1++) { $str = trim(fgets(STDIN)); $eq_l[$i1][0] = floatval(strtok($str, " ")); for ($i2 = 1; $i2 < $m; $i2++) $eq_l[$i1][$i2] = floatval(strtok(" ")); $c = strtok(" "); if ($c == '<') $cp[$i1] = -1; else if ($c == '>') $cp[$i1] = 1; else $cp[$i1] = 0; $eq_r[$i1] = floatval(strtok(" ")); } // 実行 $lp = new LP($n, $m, $z, $eq_l, $eq_r, $cp); $sw = $lp->optimize(1); // 結果の出力 $lp->result(); ?>
#***************************/
# 線形計画法 */
# 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()
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
############################################
# クラス LP(線形計画法)
# coded by Y.Suganuma
############################################
class LP :
################################
# コンストラクタ
# n1 : 制約条件の数
# m1 : 変数の数
# z1 : 目的関数の係数
# eq_l : 制約条件の左辺
# eq_r : 制約条件の右辺
# cp1 : 比較演算子
################################
def __init__(self, n1, m1, z1, eq_l, eq_r, cp1) :
# 初期設定
self.eps = 1.0e-10 # 許容誤差
self.err = 0 # エラーコード (0:正常終了, 1:解無し)
self.n = n1 # 制約条件の数
self.m = m1 # 変数の数
self.a = np.zeros(self.n) # 人為変数があるか否か
self.cp = cp1 # 比較演算子(-1:左辺<右辺, 0:左辺=右辺, 1:左辺>右辺)
self.z = z1 # 目的関数の係数
# スラック変数と人為変数の数を数える
self.m_s = 0 # スラック変数の数
self.m_a = 0 # 人為変数の数
for i1 in range(0, self.n) :
if self.cp[i1] == 0 :
self.m_a += 1
if eq_r[i1] < 0.0 :
eq_r[i1] = -eq_r[i1]
for i2 in rang(0, self.m) :
eq_l[i1][i2] = -eq_l[i1][i2]
else :
self.m_s += 1
if eq_r[i1] < 0.0 :
self.cp[i1] = -self.cp[i1]
eq_r[i1] = -eq_r[i1]
for i2 in rang(0, self.m) :
eq_l[i1][i2] = -eq_l[i1][i2]
if self.cp[i1] > 0 :
self.m_a += 1
# 単体表の作成
# 初期設定
self.mm = self.m + self.m_s + self.m_a
self.row = np.empty(self.n, np.int) # 各行の基底変数の番号
self.s = np.empty((self.n+1, self.mm+1), np.float) # 単体表
for i1 in range(0, self.n+1) :
if i1 < self.n :
self.s[i1][0] = eq_r[i1]
for i2 in range(0, self.m) :
self.s[i1][i2+1] = eq_l[i1][i2]
for i2 in range(self.m+1, self.mm+1) :
self.s[i1][i2] = 0.0
else :
for i2 in range(0, self.mm+1) :
self.s[i1][i2] = 0.0
# スラック変数
k = self.m + 1
for i1 in range(0, self.n) :
if self.cp[i1] != 0 :
if self.cp[i1] < 0 :
self.s[i1][k] = 1.0
self.row[i1] = k - 1
else :
self.s[i1][k] = -1.0
k += 1
# 人為変数
for i1 in range(0, self.n) :
if self.cp[i1] >= 0 :
self.s[i1][k] = 1.0
self.row[i1] = k - 1
self.a[i1] = 1
k += 1
# 目的関数
if self.m_a == 0 :
for i1 in range(0, self.m) :
self.s[self.n][i1+1] = -self.z[i1]
else :
for i1 in range(0 , self.m+self.m_s+1) :
for i2 in range(0 , self.n) :
if self.a[i2] > 0 :
self.s[self.n][i1] -= self.s[i2][i1]
################################
# 最適化
# sw : =0 : 中間結果無し
# =1 : 中間結果あり
# return : =0 : 正常終了
# : =1 : 解無し
################################
def optimize(self, sw) :
# フェーズ1
if sw > 0 :
if self.m_a > 0 :
print("\nphase 1")
else :
print("\nphase 2")
self.opt_run(sw)
# フェーズ2
if self.err == 0 and self.m_a > 0 :
# 目的関数の変更
self.mm -= self.m_a
for i1 in range(0, self.mm+1) :
self.s[self.n][i1] = 0.0
for i1 in range(0 , self.n) :
k = self.row[i1]
if k < self.m :
self.s[self.n][0] += self.z[k] * self.s[i1][0]
for i1 in range(0, self.mm) :
for i2 in range(0, self.n) :
k = self.row[i2]
if k < self.m :
self.s[self.n][i1+1] += self.z[k] * self.s[i2][i1+1]
if i1 < self.m :
self.s[self.n][i1+1] -= self.z[i1]
# 最適化
if sw > 0 :
print("\nphase 2")
self.opt_run(sw)
return self.err
################################
# 最適化(単体表の変形)
# sw : =0 : 中間結果無し
# =1 : 中間結果あり
################################
def opt_run(self, sw) :
self.err = -1
while self.err < 0 :
# 中間結果
if sw > 0 :
print()
self.output()
# 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1
for i1 in range(1, self.mm+1) :
if self.s[self.n][i1] < -self.eps :
q = i1 - 1
break
# 終了(最適解)
if q < 0 :
self.err = 0
# 行の選択( Bland の規則を採用)
else :
p = -1
k = -1
min = 0.0
for i1 in range(0, self.n) :
if self.s[i1][q+1] > self.eps :
x = self.s[i1][0] / self.s[i1][q+1]
if (p < 0) or (x < min) or ((x == min) and (self.row[i1] < k)) :
min = x
p = i1
k = self.row[i1]
# 解無し
if p < 0 :
self.err = 1
# 変形
else :
x = self.s[p][q+1]
self.row[p] = q
for i1 in range(0, self.mm+1) :
self.s[p][i1] /= x
for i1 in range(0, self.n+1) :
if i1 != p :
x = self.s[i1][q+1]
for i2 in range(0, self.mm+1) :
self.s[i1][i2] -= (x * self.s[p][i2])
################################
# 単体表の出力
################################
def output(self) :
for i1 in range(0, self.n+1) :
if i1 < self.n :
print("x" + str(self.row[i1]+1), end="")
else :
print(" z", end="")
for i2 in range(0, self.mm+1) :
print(" " + str(self.s[i1][i2]), end="")
print()
################################
# 結果の出力
################################
def result(self) :
if self.err > 0 :
print("\n解が存在しません")
else :
print("\n(", end="")
for i1 in range(0, self.m) :
x = 0.0
for i2 in range(0, self.n) :
if self.row[i2] == i1 :
x = self.s[i2][0]
break
if i1 == 0 :
print(x, end="")
else :
print(", " + str(x), end="")
print(") のとき,最大値 " + str(self.s[self.n][0]))
############################################
# 線形計画法
# coded by Y.Suganuma
############################################
# 入力
# 変数の数と式の数
line = sys.stdin.readline()
x = line.split()
m = int(x[0])
n = int(x[1])
cp = np.empty(n, np.int)
z = np.empty(m, np.float)
eq_r = np.empty(n, np.float)
eq_l = np.empty((n, m), np.float)
# 目的関数の係数
line = sys.stdin.readline()
x = line.split()
for i1 in range(0, m) :
z[i1] = float(x[i1])
# 制約条件
for i1 in range(0, n) :
line = sys.stdin.readline()
x = line.split()
for i2 in range(0, m) :
eq_l[i1][i2] = float(x[i2])
if x[m] == '<' :
cp[i1] = -1
elif x[m] == '>' :
cp[i1] = 1
else :
cp[i1] = 0
eq_r[i1] = float(x[m+1])
# 実行
lp = LP(n, m, z, eq_l, eq_r, cp)
lp.optimize(1)
# 結果の出力
lp.result()
/****************************/
/* 線形計画法 */
/* coded by Y.Suganuma */
/****************************/
using System;
/*************/
/* クラス LP */
/*************/
class LP
{
private int n; // 制約条件の数
private int m; // 変数の数
private int m_s; // スラック変数の数
private int m_a; // 人為変数の数
private int mm; // m + m_s + m_a
private int[] a; // 人為変数があるか否か
private int[] cp; // 比較演算子(-1:左辺<右辺, 0:左辺=右辺, 1:左辺>右辺)
private int[] row; // 各行の基底変数の番号
private double[] z; // 目的関数の係数
private double[][] s; // 単体表
private double eps; // 許容誤差
private int err; // エラーコード (0:正常終了, 1:解無し)
/******************************/
/* コンストラクタ */
/* n1 : 制約条件の数 */
/* m1 : 変数の数 */
/* z1 : 目的関数の係数 */
/* eq_l : 制約条件の左辺 */
/* eq_r : 制約条件の右辺 */
/* cp1 : 比較演算子 */
/******************************/
public LP(int n1, int m1, double[] z1, double[][] eq_l, double[] eq_r, int[] cp1)
{
// 初期設定
eps = 1.0e-10;
err = 0;
n = n1;
m = m1;
a = new int [n];
cp = new int [n];
for (int i1 = 0; i1 < n; i1++) {
a[i1] = 0;
cp[i1] = cp1[i1];
}
z = new double [m];
for (int i1 = 0; i1 < m; i1++)
z[i1] = z1[i1];
// スラック変数と人為変数の数を数える
m_s = 0;
m_a = 0;
for (int i1 = 0; i1 < n; i1++) {
if (cp[i1] == 0) {
m_a++;
if (eq_r[i1] < 0.0) {
eq_r[i1] = -eq_r[i1];
for (int i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
}
else {
m_s++;
if (eq_r[i1] < 0.0) {
cp[i1] = -cp[i1];
eq_r[i1] = -eq_r[i1];
for (int i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = -eq_l[i1][i2];
}
if (cp[i1] > 0)
m_a++;
}
}
// 単体表の作成
// 初期設定
mm = m + m_s + m_a;
row = new int [n];
s = new double [n+1][];
for (int i1 = 0; i1 < n+1; i1++)
s[i1] = new double [mm+1];
for (int i1 = 0; i1 <= n; i1++) {
if (i1 < n) {
s[i1][0] = eq_r[i1];
for (int i2 = 0; i2 < m; i2++)
s[i1][i2+1] = eq_l[i1][i2];
for (int i2 = m+1; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
else {
for (int i2 = 0; i2 <= mm; i2++)
s[i1][i2] = 0.0;
}
}
// スラック変数
int k = m + 1;
for (int i1 = 0; i1 < n; i1++) {
if (cp[i1] != 0) {
if (cp[i1] < 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
}
else
s[i1][k] = -1.0;
k++;
}
}
// 人為変数
for (int i1 = 0; i1 < n; i1++) {
if (cp[i1] >= 0) {
s[i1][k] = 1.0;
row[i1] = k - 1;
a[i1] = 1;
k++;
}
}
// 目的関数
if (m_a == 0) {
for (int i1 = 0; i1 < m; i1++)
s[n][i1+1] = -z[i1];
}
else {
for (int i1 = 0; i1 <= m+m_s; i1++) {
for (int i2 = 0; i2 < n; i2++) {
if (a[i2] > 0)
s[n][i1] -= s[i2][i1];
}
}
}
}
/*******************************/
/* 最適化 */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/* return : =0 : 正常終了 */
/* : =1 : 解無し */
/*******************************/
public int optimize(int sw)
{
// フェーズ1
if (sw > 0) {
if (m_a > 0) {
Console.WriteLine();
Console.WriteLine("phase 1");
}
else {
Console.WriteLine();
Console.WriteLine("phase 2");
}
}
opt_run(sw);
// フェーズ2
int k;
if (err == 0 && m_a > 0) {
// 目的関数の変更
mm -= m_a;
for (int i1 = 0; i1 <= mm; i1++)
s[n][i1] = 0.0;
for (int i1 = 0; i1 < n; i1++) {
k = row[i1];
if (k < m)
s[n][0] += z[k] * s[i1][0];
}
for (int i1 = 0; i1 < mm; i1++) {
for (int i2 = 0; i2 < n; i2++) {
k = row[i2];
if (k < m)
s[n][i1+1] += z[k] * s[i2][i1+1];
}
if (i1 < m)
s[n][i1+1] -= z[i1];
}
// 最適化
if (sw > 0) {
Console.WriteLine();
Console.WriteLine("phase 2");
}
opt_run(sw);
}
return err;
}
/*******************************/
/* 最適化(単体表の変形) */
/* sw : =0 : 中間結果無し */
/* =1 : 中間結果あり */
/*******************************/
void opt_run(int sw)
{
err = -1;
int p, q, k;
double x, min;
while (err < 0) {
// 中間結果
if (sw > 0) {
Console.WriteLine();
output();
}
// 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1;
for (int i1 = 1; i1 <= mm && q < 0; i1++) {
if (s[n][i1] < -eps)
q = i1 - 1;
}
// 終了(最適解)
if (q < 0)
err = 0;
// 行の選択( Bland の規則を採用)
else {
p = -1;
k = -1;
min = 0.0;
for (int i1 = 0; i1 < n; i1++) {
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];
}
}
}
// 解無し
if (p < 0)
err = 1;
// 変形
else {
x = s[p][q+1];
row[p] = q;
for (int i1 = 0; i1 <= mm; i1++)
s[p][i1] /= x;
for (int i1 = 0; i1 <= n; i1++) {
if (i1 != p) {
x = s[i1][q+1];
for (int i2 = 0; i2 <= mm; i2++)
s[i1][i2] -= x * s[p][i2];
}
}
}
}
}
}
/****************/
/* 単体表の出力 */
/****************/
void output()
{
for (int i1 = 0; i1 <= n; i1++) {
if (i1 < n)
Console.Write("x" + (row[i1]+1));
else
Console.Write(" z");
for (int i2 = 0; i2 <= mm; i2++)
Console.Write(" " + s[i1][i2]);
Console.WriteLine();
}
}
/**************/
/* 結果の出力 */
/**************/
public void result()
{
if (err > 0) {
Console.WriteLine("解が存在しません");
Console.WriteLine();
}
else {
Console.WriteLine();
Console.Write("(");
for (int i1 = 0; i1 < m; i1++) {
double x = 0.0;
for (int i2 = 0; i2 < n; i2++) {
if (row[i2] == i1) {
x = s[i2][0];
break;
}
}
if (i1 == 0)
Console.Write(x);
else
Console.Write(", " + x);
}
Console.WriteLine(") のとき,最大値 " + s[n][0]);
}
}
}
/****************/
/* main program */
/****************/
class Program
{
static void Main()
{
// 入力
// 変数の数と式の数
string[] str = Console.ReadLine().Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
int m = int.Parse(str[0]);
int n = int.Parse(str[1]);
int[] cp = new int [n];
double[] z = new double [m];
double[][] eq_l = new double [n][];
for (int i1 = 0; i1 < n; i1++)
eq_l[i1] = new double [m];
double[] eq_r = new double [n];
// 目的関数の係数
str = Console.ReadLine().Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
for (int i1 = 0; i1 < m; i1++)
z[i1] = double.Parse(str[i1]);
// 制約条件
for (int i1 = 0; i1 < n; i1++) {
str = Console.ReadLine().Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
for (int i2 = 0; i2 < m; i2++)
eq_l[i1][i2] = double.Parse(str[i2]);
if (String.Compare("<", str[m]) == 0)
cp[i1] = -1;
else if (String.Compare(">", str[m]) == 0)
cp[i1] = 1;
else
cp[i1] = 0;
eq_r[i1] = double.Parse(str[m+1]);
}
// 実行
LP lp = new LP(n, m, z, eq_l, eq_r, cp);
int sw = lp.optimize(1);
// 結果の出力
if (sw == 0)
lp.result();
else
Console.WriteLine("解がありません!");
}
}
''''''''''''''''''''''''''''
' 線形計画法 '
' coded by Y.Suganuma '
''''''''''''''''''''''''''''
Imports System.Text.RegularExpressions
Module Test
Sub Main()
' 入力
' 変数の数と式の数
Dim MS As Regex = New Regex("\s+")
Dim str() As String = MS.Split(Console.ReadLine().Trim())
Dim m As Integer = Integer.Parse(str(0))
Dim n As Integer = Integer.Parse(str(1))
Dim cp(n) As Integer
Dim z(m) As Double
Dim eq_l(n,m) As Double
Dim eq_r(n) As Double
' 目的関数の係数
str = MS.Split(Console.ReadLine().Trim())
For i1 As Integer = 0 To m-1
z(i1) = Double.Parse(str(i1))
Next
' 制約条件
For i1 As Integer = 0 To n-1
str = MS.Split(Console.ReadLine().Trim())
For i2 As Integer = 0 To m-1
eq_l(i1,i2) = Double.Parse(str(i2))
Next
If String.Compare("<", str(m)) = 0
cp(i1) = -1
ElseIf String.Compare(">", str(m)) = 0
cp(i1) = 1
Else
cp(i1) = 0
End If
eq_r(i1) = Double.Parse(str(m+1))
Next
' 実行
Dim lp1 As LP = New LP(n, m, z, eq_l, eq_r, cp)
Dim sw As Integer = lp1.optimize(1)
' 結果の出力
If sw = 0
lp1.result()
Else
Console.WriteLine("解がありません!")
End If
End Sub
'''''''''''''
' クラス LP '
'''''''''''''
Class LP
private n As Integer ' 制約条件の数
private m As Integer ' 変数の数
private m_s As Integer ' スラック変数の数
private m_a As Integer ' 人為変数の数
private mm As Integer ' m + m_s + m_a
private a() As Integer ' 人為変数があるか否か
private cp() As Integer ' 比較演算子(-1:左辺<右辺, 0:左辺=右辺, 1:左辺>右辺)
private row() As Integer ' 各行の基底変数の番号
private z() As Double ' 目的関数の係数
private s(,) As Double ' 単体表
private eps As Double ' 許容誤差
private err As Integer ' エラーコード (0:正常終了, 1:解無し)
''''''''''''''''''''''''''''''
' コンストラクタ '
' n1 : 制約条件の数 '
' m1 : 変数の数 '
' z1 : 目的関数の係数 '
' eq_l : 制約条件の左辺 '
' eq_r : 制約条件の右辺 '
' cp1 : 比較演算子 '
''''''''''''''''''''''''''''''
Public Sub New (n1 As Integer, m1 As Integer, z1() As Double, eq_l(,) As Double,
eq_r() As Double, cp1() As Integer)
' 初期設定
eps = 1.0e-10
err = 0
n = n1
m = m1
ReDim a(n)
ReDim cp(n)
For i1 As Integer = 0 To n-1
a(i1) = 0
cp(i1) = cp1(i1)
Next
ReDim z(m)
For i1 As Integer = 0 To m-1
z(i1) = z1(i1)
Next
' スラック変数と人為変数の数を数える
m_s = 0
m_a = 0
For i1 As Integer = 0 To n-1
If cp(i1) = 0
m_a += 1
If eq_r(i1) < 0.0
eq_r(i1) = -eq_r(i1)
For i2 As Integer = 0 To m-1
eq_l(i1,i2) = -eq_l(i1,i2)
Next
End If
Else
m_s += 1
If eq_r(i1) < 0.0
cp(i1) = -cp(i1)
eq_r(i1) = -eq_r(i1)
For i2 As Integer = 0 To m-1
eq_l(i1,i2) = -eq_l(i1,i2)
Next
End If
If cp(i1) > 0
m_a += 1
End If
End If
Next
' 単体表の作成
' 初期設定
mm = m + m_s + m_a
ReDim row(n)
ReDim s(n+1,mm+1)
For i1 As Integer = 0 To n
If i1 < n
s(i1,0) = eq_r(i1)
For i2 As Integer = 0 To m-1
s(i1,i2+1) = eq_l(i1,i2)
Next
For i2 As Integer = m+1 To mm
s(i1,i2) = 0.0
Next
Else
For i2 As Integer = 0 To mm
s(i1,i2) = 0.0
Next
End If
Next
' スラック変数
Dim k As Integer = m + 1
For i1 As Integer = 0 To n-1
If cp(i1) <> 0
If cp(i1) < 0
s(i1,k) = 1.0
row(i1) = k - 1
Else
s(i1,k) = -1.0
End If
k += 1
End If
Next
' 人為変数
For i1 As Integer = 0 To n-1
If cp(i1) >= 0
s(i1,k) = 1.0
row(i1) = k - 1
a(i1) = 1
k += 1
End If
Next
' 目的関数
If m_a = 0
For i1 As Integer = 0 To m
s(n,i1+1) = -z(i1)
Next
Else
For i1 As Integer = 0 To m+m_s
For i2 As Integer = 0 To n-1
If a(i2) > 0
s(n,i1) -= s(i2,i1)
End If
Next
Next
End If
End Sub
'''''''''''''''''''''''''''''''
' 最適化 '
' sw : =0 : 中間結果無し '
' =1 : 中間結果あり '
' return : =0 : 正常終了 '
' : =1 : 解無し '
'''''''''''''''''''''''''''''''
Public Function optimize(sw As Integer)
' フェーズ1
If sw > 0
If m_a > 0
Console.WriteLine()
Console.WriteLine("phase 1")
Else
Console.WriteLine()
Console.WriteLine("phase 2")
End If
End If
opt_run(sw)
' フェーズ2
Dim k As Integer
If err = 0 and m_a > 0
' 目的関数の変更
mm -= m_a
For i1 As Integer = 0 To mm
s(n,i1) = 0.0
Next
For i1 As Integer = 0 To n-1
k = row(i1)
If k < m
s(n,0) += z(k) * s(i1,0)
End If
Next
For i1 As Integer = 0 To mm-1
For i2 As Integer = 0 To n-1
k = row(i2)
If k < m
s(n,i1+1) += z(k) * s(i2,i1+1)
End If
Next
If i1 < m
s(n,i1+1) -= z(i1)
End If
Next
' 最適化
If sw > 0
Console.WriteLine()
Console.WriteLine("phase 2")
End If
opt_run(sw)
End If
Return err
End Function
'''''''''''''''''''''''''''''''
' 最適化(単体表の変形) '
' sw : =0 : 中間結果無し '
' =1 : 中間結果あり '
'''''''''''''''''''''''''''''''
Sub opt_run(sw As Integer)
err = -1
Dim p As Integer
Dim q As Integer
Dim k As Integer
Dim x As Double
Dim min As Double
Do While err < 0
' 中間結果
If sw > 0
Console.WriteLine()
output()
End If
' 列の選択(巡回を防ぐため必ずしも最小値を選択しない,Bland の規則)
q = -1
Dim ii As Integer = 1
Do While ii <= mm and q < 0
If s(n,ii) < -eps
q = ii - 1
End If
ii += 1
Loop
' 終了(最適解)
If q < 0
err = 0
' 行の選択( Bland の規則を採用)
Else
p = -1
k = -1
min = 0.0
For i1 As Integer = 0 To n-1
If s(i1,q+1) > eps
x = s(i1,0) / s(i1,q+1)
If p < 0 or x < min or (x = min and row(i1) < k)
min = x
p = i1
k = row(i1)
End If
End If
Next
' 解無し
If p < 0
err = 1
' 変形
Else
x = s(p,q+1)
row(p) = q
For i1 As Integer = 0 To mm
s(p,i1) /= x
Next
For i1 As Integer = 0 To n
If i1 <> p
x = s(i1,q+1)
For i2 As Integer = 0 To mm
s(i1,i2) -= x * s(p,i2)
Next
End If
Next
End If
End If
Loop
End Sub
''''''''''''''''
' 単体表の出力 '
''''''''''''''''
Sub output()
For i1 As Integer = 0 To n
If i1 < n
Console.Write("x" & (row(i1)+1))
Else
Console.Write(" z")
End If
For i2 As Integer = 0 To mm
Console.Write(" " & s(i1,i2))
Next
Console.WriteLine()
Next
End Sub
''''''''''''''
' 結果の出力 '
''''''''''''''
Public Sub result()
If err > 0
Console.WriteLine("解が存在しません")
Console.WriteLine()
Else
Console.WriteLine()
Console.Write("(")
For i1 As Integer = 0 To m-1
Dim x As Double = 0.0
For i2 As Integer = 0 To n-1
If row(i2) = i1
x = s(i2,0)
Exit For
End If
Next
If i1 = 0
Console.Write(x)
Else
Console.Write(", " & x)
End If
Next
Console.WriteLine(") のとき,最大値 " & s(n,0))
End If
End Sub
End Class
End Module
| 情報学部 | 菅沼ホーム | 目次 | 索引 |