Мета роботи: вивчення симплекс методу для знаходження розв’язку задач лінійного програмування .
План
Короткі теоретичні відомості.
Постановка задачі
Симплекс метод розв’язаний за допомогою симлекс таблиць з додаванням змінних.
Розв’язання за допомогою пакету програм SimplexWin
Розв’язання за допомогою власної програми.
Хід роботи
1. Короткі теоретичні відомості
Симплекс метод - універсальний метод для вирішення лінійної системи рівнянь або нерівностей і лінійного функціоналу.
Для приведення системи обмежень нерівностей до канонічного виду, необхідно в системі обмежень виділити одиничний базис.
I. Обмеження виду «?» - ресурсні обмеження. Справа знаходиться те що ми використовуємо на виробництві, ліворуч - те що отримуємо. При таких обмеженнях вводять додаткові змінні з коефіцієнтом «+1», що утворюють одиничний базис. У цільову функцію ці змінні увійдуть з коефіцієнтом «0».
II. Обмеження виду «=». Часто буває, що незважаючи на те що обмеження мають вигляд рівності, одиничний базис не виділяється або важко виділяється. В цьому випадку вводяться штучні змінні для створення одиничного базису - Yi. В систему обмежень вони входять з коефіцієнтом «1», а в цільову функцію з коефіцієнтом «M», що прагнуть до нескінченності (при Fmin - «+ M», при Fmax - «-M»).
III. Обмеження виду «?» - планові обмеження. Додаткові змінні (X), що несуть певний економічний зміст - перевитрата ресурсів або перевиконання плану, перевиробництво, додаються з коефіцієнтом «-1», в цільову функцію - з коефіцієнтом «0». А штучні змінні (Y) як у попередньому випадку.
Алгоритм симплекс методу
Нехай система приведена до канонічного виду.
X1+ q1,m+1 Xm+1 + …. + q1,m+n Xm+n = h1
X2+ q1,m+1 Xm+1 + …. + q1,m+n Xm+n = h1 (1)
X3+ q1,m+1 Xm+1 + …. + q1,m+n Xm+n = h1
……………………………………………………………….
Xm+ qm,m+1 Xm+1 + …. + qm,m+n Xm+n =hm
У ній m базисних змінних, k вільних змінних. m + k = n - всього змінних.
Fmin = C1X1 + C2X2 + C3X3 + .... + CnXn
Всі hi повинні бути більше або дорівнюють нулю, де i = 1,2 ... m. На першому кроці в якості допустимого рішення приймаємо всі Xj = 0 (j = m +1, m +2, ..., m + k). При цьому всі базисні змінні Xi = Hi.
Для подальших міркувань обчислень будемо користуватися першою симплекс таблицею.
Таблица 1 –Перша симплес таблиця .
C
Б
H
C1
C2

Cm
Cm+1

Cm+k




X1
X2

Xm
Xm+1

Xm+k

C1
C2
C3
:
:
Cm
X1
X2
X3
:
:
Xm
h1
h2
h3
:
:
hm
1
0
0
:
:
0
0
1
0
:
:
0
:
:
:
:
:
:
0
0
0
:
:
0
q1,m+1
q2,m+1
q3,m+1
:
:
qm,m+1
:
:
:
:
:
:
q1,m+k
q2,m+k
q3,m+k
:
:
qm,m+k


F=
F0
??
??

?m
?m+1

?m+k


Перший стовпчик-коефіцієнти в цільової функції при базисних змінних.
Другий стовпчик - базисні змінні.
Третій стовпчик - вільні члени (hi?0).
Самий верхній рядок - коефіцієнти при цільовій функції.
Другий верхній рядок - змінні, що входять в цільову функцію і в систему обмежень.
Основне поле симплекс методу - система коефіцієнтів з рівняння.
Останній рядок - служить для того, щоб відповісти на питання: «оптимальний план чи ні».
2. Постановка задачі
Розв’язати задачу лінійного програмування симплекс методом (номер завдання відповідає двом останнім цифрам залікової книжки студента, крім цифр 00 – які відповідають завданню під номером100)
Варіант 32
F(x1,x2) = x1 + x2 max ;
3x1 - 2x2 -6,
x1+ 2x2 3,
3x1 0, 5 x2 0.
2. Розв’язання без використання пакетів програм.

Cимплекс метод розв’язаний за допомогою сиплекс таблиць
З додаванням додаткових змінних .
Умова:
F(X) = 14x1 + 10x2
7x1 + 5x2?7
7x1 - 5x2?35
x1 - x2?0
Вирішимо пряму задачу лінійного програмування симплексним методом, з використанням симплексного таблиці.Оскільки в правій частині присутні негативні значення, помножимо відповідні рядки на (-1).Визначимо максимальне значення цільової функції F (X) = x1 + x2 при наступних умовах-обмежень.- 3x1 + 2x2 ? 6x1 + 2x2 ? 3Для побудови першого опорного плану систему нерівностей приведемо до системи рівнянь шляхом введення додаткових змінних (перехід до канонічної формі).-3x1 + 2x2 + 1x3 + 0x4 = 61x1 + 2x2 + 0x3-1x4 = 3Введемо штучні змінні x: в 2-м рівність вводимо змінну x5;-3x1 + 2x2 + 1x3 + 0x4 + 0x5 = 61x1 + 2x2 + 0x3-1x4 + 1x5 = 3Для постановки задачі на максимум цільову функцію запишемо так:F (X) = x1 + x2 - Mx5 > maxЗ рівнянь виражаємо штучні змінні: x5 = 3-x1-2x2 + x4які підставимо в цільову функцію:F (X) = (1 +1 M) x1 + (1 +2 M) x2 + (-1M) x4 + (-3M) > maxМатриця коефіцієнтів A = a (ij) цієї системи рівнянь має вигляд:
Вирішимо систему рівнянь щодо базисних змінних:x3, x5,Вважаючи, що вільні змінні рівні 0, отримаємо перший опорний план:X1 = (0,0,6,0,3)
Базис
БП
x 1
x 2
x 3
x 4
x 5
x 6
z 1

x3
6
-3
2
1
0
0
0
0

z1
3
1
2
0
-1
0
0
1

x5
3
1
0
0
0
1
0
0

x6
5
0
1
0
0
0
1
0

ИС
-3M
-M-1
-2M-1
0
M
0
0
0


Переходимо до основного алгоритму симплекс-метода.
Ітерація № 0.Поточний опорний план неоптимальний, тому що в індексному рядку знаходяться негативні коефіцієнти.В якості ведучого виберемо стовпець, відповідний змінної x2, так як це найбільший коефіцієнт за модулем.Обчислимо значення Di по рядках як частка від ділення: bi / ai2і з них виберемо найменше:Отже, 2-ий рядок є провідною.Дозволяє елемент дорівнює (2) і стоїть на перетині провідного стовпця і ведучою рядка
Базис
B
x1
x2
x3
x4
x5
min

x3
6
-3
2
1
0
0
3

x5
3
1
2
0
-1
1
11/2

F(X1)
-3M
-1-1M
-1-2M
0
1M
0
0


Отримуємо нову симплекс-таблицю:
Базис
B
x1
x2
x3
x4
x5

x3
3
-4
0
1
1
-1

x2
11/2
1/2
1
0
-1/2
1/2

F(X1)
11/2
-1/2
0
0
-1/2
1/2+1M


Ітерація № 1.Поточний опорний план неоптимальний, тому що в індексному рядку знаходяться негативні коефіцієнти.В якості ведучого виберемо стовпець, відповідний змінної x4, так як це найбільший коефіцієнт за модулем.Обчислимо значення Di по рядках як частка від ділення: bi / ai4і з них виберемо найменше:Отже, 1-а рядок є провідною.Дозволяє елемент дорівнює (1) і стоїть на перетині провідного стовпця і ведучою рядка.
Базис
БП
x 1
x 2
x 3
x 4
x 5
x 6
z 1

x3
3
-4
0
1
1
0
0
-1

x2
3/2
1/2
1
0
-1/2
0
0
1/2

x5
3
1
0
0
0
1
0
0

x6
7/2
-1/2
0
0
1/2
0
1
-1/2

ИС
3/2
-1/2
0
0
-1/2
0
0
M+1/2



Отримуємо нову симплекс-таблицю:
Базис
БП
x 1
x 2
x 3
x 4
x 5
x 6
z 1

x3
15
0
8
1
-3
0
0
3

x1
3
1
2
0
-1
0
0
1

x5
0
0
-2
0
1
1
0
-1

x6
5
0
1
0
0
0
1
0

ИС
3
0
1
0
-1
0
0
M+1


Базис
БП
x 1
x 2
x 3
x 4
x 5
x 6
z 1

x3
15
0
2
1
0
3
0
0

x1
3
1
0
0
0
1
0
0

x4
0
0
-2
0
1
1
0
-1

x6
5
0
1
0
0
0
1
0

ИС
3
0
-1
0
0
1
0
M


Остаточний варіант симплекс-таблиці:
Базис
БП
x 1
x 2
x 3
x 4
x 5
x 6
z 1

x3
5
0
0
1
0
3
-2
0

x1
3
1
0
0
0
1
0
0

x4
10
0
0
0
1
1
2
-1

x2
5
0
1
0
0
0
1
0

ИС
8
0
0
0
0
1
1
M




3. Розв’язання з допомогою пакету програм SimplexWin
Cимплекс метод з додаванням змінних , розв’язаний за допомогою сиплекс таблиць .
Ввід даних :
/
Крок 1:
/
Крок 2:
/
Крок 3:
/
Крок 4:
/
Крок 5:
/
/

4. Розв’язання за допомогою власної програми.

Програма написана мовою С++
Для правильного вирішення система лінійних обмежень повинна бути приведена до канонічного виду.
При запуску програми потрібно ввести кількість рівнянь обмежень (rows) і найбільший індекс змінної (cols).
Після цього потрібно послідовно ввести коефіцієнти рівнянь (xi) та їх праві частини (b), а також коефіцієнти цільової функції. Якщо який-небудь коефіцієнт відсутній, слід ввести нуль.
Для виведення результату потрібно натиснути пробіл.
Якщо для вирішення завдання були введені додаткові перемінні або штучні базиси, то їх потрібно виключити з підсумкового відповіді.
Лістинг програми main.cpp
#include "stdafx.h"
#include <iostream>
#include <cmath>
#include <fstream>
#include <sstream>
#include <string>
#include "user_data.h"
#include "simplex.h"
using std::cout;
using std::endl;
void simplex::init()
{
int i, j;
func = 0;
sv = new double *[num_l];
for (i = 0; i < num_l; i++)
sv[i] = new double [num_v * 2];
for (i = 0; i < num_l; i++) {
for (j = 0; j < num_v; j++)
sv[i][j] = system[i][j];
for (; j < num_v * 2; j++)
if (i + num_v == j)
if (way)
sv[i][j] = 1;
else
sv[i][j] = -1;
else
sv[i][j] = 0;
}
istr = new double [num_v * 2];
bv = new double *[num_l];
for (i = 0; i < num_l; i++) {
bv[i] = new double [2];
bv[i][0] = i + num_v;
bv[i][1] = fm[i];
}
for (i = 0; i < num_v * 2; i++)
if (i < num_v)
istr[i] = function[i] * -1;
else
istr[i] = 0;
i_lcol = 0;
for (i = 0; i < num_v * 2 - 1; i++) {
if (istr[i] < 0)
if (fabs(istr[i + 1]) > fabs(istr[i]))
i_lcol = i + 1;
}
th = new double [num_l];
for (i = 0; i < num_l; i++)
th[i] = bv[i][1] / sv[i][i_lcol];
i_lrow = 0;
for (i = 0; i < num_l - 1; i++)
if (th[i] > th[i + 1])
i_lrow = i + 1;
alm = sv[i_lrow][i_lcol];
print_result_to_file(0);
}
bool simplex::plane_is_valid()
{
int i;
bool result = true;
if (way)
for (i = 0; i < num_v * 2; i++)
if (istr[i] < 0) {
result = false;
break;
}
if (!way)
for (i = 0; i < num_v * 2; i++)
if (istr[i] >= 0) {
result = false;
break;
}
return result;
}
bool simplex::function_is_undefined()
{
int i;
for (i = 0; i < num_l; i++)
if (th[i] < 0) {
return false;
}
return true;
}
void simplex::gen_plane()
{
int i, j, it_num = 0;
double A, B;
while (!plane_is_valid() && function_is_undefined()) {
A = bv[i_lrow][1];
B = istr[i_lcol];
func -= A * B / alm;
double *tmp_bv = new double [num_l];
bv [i_lrow][0] = i_lcol;
A = bv[i_lrow][1];
for (i = 0; i < num_l; i++) {
B = sv[i][i_lcol];
tmp_bv[i] = bv[i_lrow][1];
if (i != i_lrow)
tmp_bv[i] = bv[i][1] - A * B / alm;
else
tmp_bv[i] /= alm;
}
for (i = 0; i < num_l; i++)
bv[i][1] = tmp_bv[i];
double *tmp_istr = istr;
B = istr[i_lcol];
for (i = 0; i < num_v * 2; i++) {
A = sv[i_lrow][i];
tmp_istr[i] = istr[i] - A * B / alm;
}
istr = tmp_istr;
double **tmp_sv = new double *[num_l];
for (i = 0; i < num_l; i++)
tmp_sv[i] = new double [num_v * 2];
for (i = 0; i < num_l; i++)
for (j = 0; j < num_v * 2; j++) {
tmp_sv[i][j] = sv[i][j];
A = sv[i_lrow][j];
B = sv[i][i_lcol];
if (i == i_lrow)
tmp_sv[i][j] /= alm;
else
tmp_sv[i][j] = sv[i][j] - A * B / alm;
}
sv = tmp_sv;
i_lcol = 0;
for (i = 0; i < num_l; i++)
th[i] = bv[i][1] / sv[i][i_lcol];
i_lrow = 0;
for (i = 0; i < num_l -1; i++)
if (th[i] > th[i + 1])
i_lrow = i + 1;
alm = sv[i_lrow][i_lcol];
it_num++;
print_result_to_file(it_num);
}
if (!function_is_undefined())
cout << "zZilova funkzija ne obmeshena , dana zadasha nemaje rishenn" << endl;
else {
cout << "f(x) = " << func << "" << endl;
for (i = 0; i < num_l; i++) {
cout << "x" << bv[i][0] + 1 << " = " << bv[i][1] << endl;
}
cout << "Resultati zapisani u table.txt" << endl;
}
}
void simplex::print_result_to_file(int it_num)
{
int i, j;
if (!it_num) {
table << "Задана цільова функція:" << endl;
std::stringstream f_x;
f_x << "f(x) = ";
for (i = 0; i < num_v; i++) {
if (!i)
f_x << function[i] << "x" << i + 1 << " ";
else {
if (function[i] < 0)
f_x << "- " << fabs(function[i]) << "x" << i + 1 << " ";
if (function[i] > 0)
f_x << "+ " << function[i] << "x" << i + 1 << " ";
}
}
std::string minmax;
if (way)
minmax = "max";
else
minmax = "min";
f_x << "=> " << minmax << "" << endl;
table << f_x.str();
table << "І система рівнянь :" << endl;
std::stringstream math_sys;
std::string math_sign;
for (i = 0; i < num_l; i++) {
for (j = 0; j < num_v; j++) {
if (!j)
math_sys << system[i][j] << "x" << j + 1 << " ";
else
if (system[i][j] == 1)
if (!j)
math_sys << "x" << j + 1 << " ";
else
math_sys << "+ x" << j + 1 << " ";
else
if (system[i][j] == -1)
if (!j)
math_sys << "-x" << j + 1 << " ";
else
math_sys << "- x" << j + 1 << " ";
else {
if (system[i][j] < 0)
math_sys << "- " << fabs(system[i][j])<< "x" << j + 1 << " ";
else
math_sys << "+ " << system[i][j] << "x" << i + 1 << " ";
if (!sign[i])
math_sign = "<=";
if (sign[i] == 1)
math_sign = "=";
if (sign[i] == 2)
math_sign = ">=";
}
}
math_sys << math_sign << " " << fm[i];
math_sys << endl;
}
std::string min_or_max;
if (way)
min_or_max = "максимум";
else
min_or_max = "мінімум";
table << math_sys.str() << endl;
table << "Вирішимо дану задачу на " << min_or_max << " методом симплексних таблиц.Побудуємо перший опорний план (таблицю):" << endl;
}
for (i = 0; i < num_l; i++) {
table << "x" << bv[i][0] + 1 << " " << bv[i][1] << " ";
for (j = 0; j < num_v * 2; j++)
table << sv[i][j] << " ";
if (!plane_is_valid())
table << th[i];
table << "" << endl;
}
table << "f(x) " << func << " ";
for (i = 0; i < num_v * 2; i++)
table << istr[i] << " ";
table << "";
if (plane_is_valid()) {
if (plane_is_valid() && function_is_undefined())
table << "Danij plan e optimalnim i ne potrrebuje pokrashennja. Rishennja najdeno." << endl;
std::ofstream outfile ("table.txt");
outfile << table.str();
}
else {
std::string ln_or_gn;
if (way)
ln_or_gn = "nehativne";
else
ln_or_gn = "pozetivne";
std::stringstream num_of_plane;
if (!it_num)
num_of_plane << "1 opornij plan";
else
num_of_plane << it_num + 1 << "-j plan takosh";
table << "" << num_of_plane.str() << " ne javlajetsja optimalnim , oskilki v indeksnomu rjadku znahodjantsja " << ln_or_gn << " elementi.Yoho neobhidno pokrash4iti." << endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL, "Russian");
simplex *ud = new simplex;
ud->get_data_from_user();
ud->init();
ud->gen_plane();
return 0;
}
Лістинг програми user_data.cpp
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib>
#include "user_data.h"
#include <cmath>
#include <fstream>
#include <sstream>
#include "simplex.h"
using namespace std;

void error(int err_no)
{
switch(err_no) {
case 0:
cout << "Vi vveli nekorektne znashennja." << endl;
break;
case 1:
cout << "Vi ne moshete zadati menshe 2 rivnjan." << endl;
break;
case 2:
cout << "Vi ne moshete zadati bilshe 500 rivnjan." << endl;
break;
case 3:
cout << "Vi ne moshete zadati menshe 2 zminnih." << endl;
break;
case 4:
cout << "Vi ne moshete zadati bilshe 500 rivnjan." << endl;
break;
}
}

void user_data::get_data_from_user()
{
string num_limits, num_vars, s_var, fr_m, sn, func, w;
int i, j;
bool validator = false;


do {
cout << "Vvedit kilkist rivnjan sistemi: ";
getline(cin, num_limits);
if (atoi(num_limits.c_str()) < 2)
error(1);
else if (atoi(num_limits.c_str()) > 500)
error(2);
else
validator = true;

} while (!validator);

num_l = atoi(num_limits.c_str());
validator = false;

do {
cout << "Vvedit kilkist zminnih pri zilovij funkziji: ";
getline(cin, num_vars);
if (atoi(num_vars.c_str()) < 2)
error(3);
else if (atoi (num_vars.c_str()) > 500)
error(4);
else
validator = true;
} while (!validator);

num_v = atoi(num_vars.c_str());
validator = false;

function = new double [num_v];
system = new double *[num_l];
for (i = 0; i < num_l; i++)
system[i] = new double [num_v];
fm = new double [num_l];
sign = new int [num_l];

cout << "Zapovnit koephizienty pry zilovij funkzii" << endl;

for (i = 0; i < num_v; i++) {
do {
cout << " Vvedit koephizienti zilovoji funkziji pri x" << i + 1 << ": ";
getline(cin, func);
if (atof(func.c_str()) == 0)
error(0);
else {
validator = true;
function[i] = atof(func.c_str());
}
} while (!validator);
validator = false;
}

do {
cout << "Vvedit naprjamlenna zilovoji funkziji ( min, max ) : ";
getline(cin, w);
if (w == "max" || w == "MAX" || w == "min" || w == "MIN") {
validator = true;
if (w == "max" || w == "MAX")
way = true;
else
way = false;
}
else
error (0);

} while (!validator);
cout << "Zapovnit sistemu rivnjan" << endl;

for (i = 0; i < num_l; i++) {
cout << "Zapovnit " << i + 1 << "-е rivnjannja." << endl;
for (j = 0; j < num_v; j++) {
do {
cout << "Vvedit koephizient pri x" << j + 1 << ": ";
getline(cin, s_var);
if (atof(s_var.c_str()) == 0)
error (0);
else {
validator = true;
}
} while (!validator);
system[i][j] = atof(s_var.c_str());
validator = false;
}

do {
cout << "Vvedit znak pry " << i + 1 << "-mu rivnjanni ( <=, =, >= ) : ";
getline(cin, sn);
if (sn == "<=" || sn == "=" || sn == ">=") {
validator = true;
if (sn == "<=")
sign[i] = 0;
if (sn == "=")
sign[i] = 1;
if (sn == ">=")
sign[i] = 2;
}
else
error(0);
} while (!validator);

validator = false;

do {
cout << "Vvedit znashennja vilnoho chlena (Bi) pri " << i + 1 << "-mu rivnjanni: ";
getline(cin, fr_m);
if (atof(fr_m.c_str()) == 0)
error(0);
else
validator = true;
} while (!validator);

fm[i] = atof(fr_m.c_str());
validator = false;

cout << endl;
}

}
Лістинг хідер файлу simplex.h
#ifndef _SIMPLEX_H_
#define _SIMPLEX_H_

#include <sstream>
#include "stdafx.h"
#include "user_data.h"

class simplex : public user_data {
public:
void init();
void gen_plane();
bool plane_is_valid();
bool function_is_undefined();
void print_result_to_file(int it_num);
private:
double func;
double **bv;
double **sv;
double *istr;
double *th;
double alm;
int i_lrow;
int i_lcol;
std::stringstream table;
};

#endif /* _SIMPLEX_H_ */
Лістинг хідер файлу user_data.h
#ifndef _USER_DATA_H_
#define _USER_DATA_H_
#include "stdafx.h"
class user_data {
public:
void get_data_from_user();
void user_data_is_valid();
protected:
double *function;
double *fm;
double **system;
int *sign;
int num_v;
int num_l;
bool way;
};

#endif /* _USER_DATA_H_ */
Висновок: на цій лабораторній роботі я набув навиків розв’язку задачі лінійного програмування симплекс-методом.

Міністерство освіти та науки, молоді та спорту України
НУ «ЛЬВІВСЬКА ПОЛІТЕХНІКА»
Кафедра АСУ
/
Лабораторна робота №3-4
з дисципліни “Математичні методи дослідження операцій”
Виконав:
студент групи КН-22
Саврук Сергій
Прийняв:
старший викладач
Балич Б. І.
Львів – 2012