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