Федеральне агентство з освіти РФ
Федеральне державне освітній заклад
Середньої професійної освіти
Барнаульський будівельний коледж
Курсова робота.
З дисципліни: «Математичні методи»
На тему: «Рішення задач лінійного програмування симплекс методом»
Виконав: Нунгесер М.В.
Спеціальність: ПОВТ
Група: 0881
Викладач: Клепікова М.М.
Барнаул 2010
Зміст:
Введення
Лінійне програмування
Симплекс метод
Постановка завдання
Розробка алгоритму
Рішення завдання
Програмна реалізація на мові Delphi
Додаток
Висновок
Список використаної літератури
Введення
В останні роки в прикладній математиці велика увага приділяється новому класу задач оптимізації, які полягають у знаходженні в заданій області точок найбільшого або найменшого значення певної функції, що залежить від великого числа змінних. Це так звані завдання математичного програмування, що виникають у найрізноманітніших галузях людської діяльності і перш за все в економічних дослідженнях, в практиці планування і організації виробництва. Вивчення цього кола завдань і методів їх вирішення призвело до створення нової наукової дисципліни, що отримала пізніше назву лінійного програмування. В кінці 40-х років американським математиком Дж. Данцигом був розроблений ефективний метод вирішення даного класу завдань - симплекс-метод. До завдань, що вирішуються цим методом у межах математичного програмування належать такі типові економічні завдання як «Визначення найкращого складу суміші», «Завдання про оптимальний плані випуску продукції», «Оптимізація міжгалузевих потоків», «Завдання про вибір виробничої програми», «Транспортна задача» , «Завдання розміщення», «Модель Неймана розширюється економіки» та інші. Вирішення таких завдань дає великі вигоди як народному господарству в цілому, так і окремих його галузях.
Рішення задач математичного програмування за допомогою симплекс-методу традиційними способами вимагає витрат великої кількості часу. У зв'язку з бурхливим розвитком комп'ютерної техніки в останні десятиліття природно було очікувати, що обчислювальна потужність сучасних ЕОМ буде застосована для вирішення зазначеного кола завдань.
Лінійне програмування
Лінійне програмування - математична дисципліна, присвячена теорії та методів розв'язання задач про екстремуму лінійних функцій на множинах n-мірного векторного простору, що задаються системами лінійних рівнянь і нерівностей.
Лінійне програмування є окремим випадком опуклого програмування, яке в свою чергу є окремим випадком математичного програмування. Одночасно воно - основа декількох методів вирішення завдань цілочисельного і нелінійного програмування. Одним з узагальнень лінійного програмування є дробово-лінійне програмування.
Багато властивостей задач лінійного програмування можна інтерпретувати також як властивості многогранників і таким чином геометрично формулювати і доводити їх.
Математичне формулювання задачі лінійного програмування
Потрібно визначити максимум лінійної цільової функції (лінійної форми)
за умов
Іноді на x i також накладається деякий набір обмежень у вигляді рівностей, але від них можна позбутися, послідовно висловлюючи одну змінну через інші і підставляючи її в усіх інших равенствах і нерівностях (а також у функції f).
Таке завдання називають «основний» або «стандартної» в лінійному програмуванні. Найбільш відомим і широко застосовуваним на практиці для вирішення загальної задачі лінійного програмування (ЛП) є симплекс метод.
Симплекс метод
Симплекс метод - метод лінійного програмування, який реалізує раціональний перебір базисних допустимих рішень, у вигляді кінцевого ітеративного процесу, необхідно покращувати значення цільової функції на кожному кроці.
Застосування симплекс-методу для задачі лінійного програмування передбачає попереднє приведення її формальної постановки до канонічної форми з n невід'ємними змінними: (X 1, ..., X n), де потрібно мінімізація лінійної цільової функції при m лінійних обмеженнях типу рівностей. Серед змінних завдання вибирається початковий базис з m змінних, для визначеності (X 1, ..., X m), які повинні мати невід'ємні значення, коли решта (nm) вільні змінні рівні 0. Цільова функція та обмеження рівності перетворяться до діагональної формі щодо базисних змінних, змінних, де кожна базисна змінна входить лише в одне рівняння з коефіцієнтом 1.
Дана формальна модель задачі лінійного програмування зазвичай задається у формі, так званої симплекс-таблиці, зручної для виконання операцій симплекс-методу:
Симплекс-таблиця
1 | X 1 | X 2 | ... | X m | X m +1 | ... | X n | |
X 0 | A 0,0 | 0 | 0 | ... | 0 | A 0, m +1 | ... | A 0, n |
X 1 | A 1,0 | 1 | 0 | ... | 0 | A 1, m +1 | ... | A 1, n |
X 2 | A 2,0 | 0 | 1 | ... | 0 | A 2, m +1 | ... | A 2, n |
... | ... | ... | ... | ... | ... | ... | ... | ... |
X m | A m, 0 | 0 | 0 | ... | 1 | A m, m +1 | ... | A m, n |
Верхній рядок симплекс-таблиці представляє цільову функцію завдання. Кожен рядок симплекс-таблиці, крім першої, відповідає певному обмеженню-рівності завдання. Вільні члени обмежень складають крайній лівий стовпець таблиці. Зліва від таблиці записані поточні базисні змінні (X 1, ..., X m). Зверху від таблиці наведено набір всіх змінних задачі, де X m +1, ..., X n - вільні змінні завдання.
На початковому кроці алгоритму симплекс-методу має бути вибрано базисне допустиме рішення (X 1, ..., X m)> = 0 при X j = 0 (j = m +1, ..., n), отже, всі вільні члени обмежень A i, 0> = 0 (i = 1, ..., m). Коли ця умова виконана, симплекс-таблиця називається прямо-допустимої, тому що в цьому випадку базисні змінні, рівні A i, 0, визначають дозволене рішення прямої задачі лінійного програмування. Якщо всі коефіцієнти цільової функції A 0, j> = 0 (j = 1, ..., m), то симплекс-таблиця називається двояко-допустимої, оскільки відповідне рішення є допустимим для двоїстої задачі лінійного програмування.
Якщо симплекс-таблиця є одночасно прямо і двояко допустимої, тобто одночасно всі A i, 0> = 0 і A 0, j> = 0, то рішення оптимально.
Дійсно, оскільки допустимими є лише невід'ємні значення керованих параметрів, то зміна цільової функції за рахунок варіації вільних змінних, через які вона виражена, можливо тільки в бік збільшення, тобто, буде погіршуватися. Якщо серед її коефіцієнтів є A 0, j <0, то значення цільової функції ще можна зменшити (т.e. поліпшити), збільшуючи значення будь-якої вільної змінної X j з негативним коефіцієнтом A 0, j при побічну зменшенні базисних змінних, щоб залишалися справедливі обмеження завдання. Теоретично можна використовувати будь-яку вільну змінну X j з A 0, j <0, але на практиці зазвичай діють у відповідності зі стратегією найшвидшого спуску, вибираючи мінімальний елемент A 0, p <0 з усіх негативних A 0, j <& nbsp0:
A 0, p = min A 0, j <0.
j
Стовпець p симплекс-таблиці, що відповідає обраному коефіцієнту A 0, p <0, називається провідним стовпцем. Вільна мінлива ведучого шпальти повинна бути введена в базис замість однієї з поточних базисних змінних. Очевидно, з базису слід виключити таку змінну X q, яка раніше інших звертається в нуль при збільшенні змінної X p ведучого шпальти.
Її індекс легко визначити, якщо серед позитивних елементів ведучого шпальти p знайти елемент, здатний мінімізувати відношення (A i, 0 / A i, p):
A q, 0 A i, 0
------ = Min ------, i = 1 ,..., m.
A q, p i A i, p
Елемент A q, p називається провідним елементом, c Троках q симплекс-таблиці, що містить ведучий елемент, називається, відповідно, провідною рядком. Змінна провідною рядки X q замінюється в базисі змінної ведучого шпальти X p і стає вільною змінної з значенням 0, у той час як нова базисна змінна X p досягне максимально можливого значення, рівного: max X p = (A q, 0 / A q, p).
Після зазначеного взаимообразно обміну змінними X p і X q між наборами вільних і базисних змінних потрібно модифікувати вихідну канонічну модель задачі шляхом приведення її до діагональної формі щодо нової множини базисних змінних. Для зазначеного перетворення можна формально використовувати процедуру виключення Гауса, яка, як відомо, складається з двох елементарних операцій, що застосовуються до системи алгебраїчних рівнянь (в даному випадку обмежень - рівностей):
множення рівняння E 1 (X) = 0 на константу K 1 і заміна рівняння E 1 (X) = 0 рівнянням K 1 * E 1 (X) = 0;
складання рівнянь E 1 (X) = 0 і E 2 (X) = 0 c наступною заміною рівняння E 2 (X) = 0 рівнянням E 1 (X) + E 2 (X) = 0.
Винятки Гауса дозволяють привести систему рівнянь до діагональної формі щодо бажаного безлічі змінних. У даному випадку виключення Гауса застосовується так, щоб всі елементи симплекс-таблиці у провідному стовпці, крім ведучого елемента A q, p, стали нульовими, а ведучий елемент став рівним одиниці:
A i, p = 0, якщо i не дорівнює q
і
A i, p = 1, якщо i = q.
Зазначені кроки симплекс-методу повторюються, поки не буде отримана симплекс-таблиця, яка одночасно є прямо і двояко допустимої. Якщо покладе в такій симплекс-таблиці поточні базисні змінні рівними A i, 0, а вільні - нулю, то буде отримано оптимальне рішення.
Практика застосування симплекс методу показала, що кількість ітерацій, необхідних для вирішення задачі лінійного програмування зазвичай коливається від 2m до 3m, хоча для деяких спеціально побудованих завдань обчислення за правилами симплекс методу перетворюються на прямий перебір базисних допустимих рішень. Проте, важкі для симплекс методу завдання на практиці зустрічаються украй рідко, що пояснює широке розповсюдження і більшу популярність даного методу лінійного програмування в порівнянні з іншими підходами.
Постановка завдання
На звірофермі можуть вирощуватися норки, видри і нутрії. Для забезпечення нормальних умов їх вирощування використовується 3 види кормів. Кількість корму кожного виду, яке повинні отримувати звіри в середньому наведено в таблиці:
Кількість одиниць корму, яке щодня повинні отримувати | ||||
Вид корму | Норка | Видра | Нутрія | Загальна кількість корму |
I | 4 | 2 | 5 | 190 |
II | 5 | 3 | 4 | 320 |
III | 7 | 9 | 5 | 454 |
Прибуток від реалізації однієї шкурки, руб. | 150 | 320 | 350 |
У таблиці вказана загальна кількість корму кожного виду, яке може бути використане звіроферми, і прибуток від реалізації однієї шкурки звірка.
Визначити, скільки звірків кожного виду слід вирощувати на звірофермі, щоб прибуток від реалізації шкурок була максимальною.
Алгоритм розв'язання задач симплекс - методом
Поставлена описова завдання переводиться в математичну форму (цільова функція та обмеження).
Отримане математичний опис призводять до канонічної форми.
Канонічну форму призводять до матричному увазі.
Шукають перший допустиме рішення. Для цього матриця повинна бути правильною. Матриця в ЗЛП називається правильною, якщо вона містить мінімум m правильних (базисних) стовпців, де m - число рядків в матриці. Стовпець у канонічній ЗЛП називається правильним (базисним), якщо всі його елементи дорівнюють нулю, крім єдиного рівного одиниці.
Якщо матриця не є правильною, то її потрібно зробити такої з допомогою штучного базису. Для цього в матрицю потрібно дописати стільки базисних стовпців, щоб їх загальна кількість разом з уже наявними базисними стовпцями становило m. Після цього переходять до пункту 6. Якщо штучний стовпець виходить з базису, то його видаляють з матриці. Якщо вилучені всі штучні стовпці, то отримано перше допустиме рішення. Якщо штучні елементи не вдається вивести з базису, то система не має рішень.
Будують послідовність матриць. Потрібно визначити провідний стовпець, провідну рядок і ведучий елемент. Елемент, відповідний провідною рядку, видаляється з базису, а на його місце ставлять елемент, відповідний ведучому стовпцю. Складають рівняння перерахунку матриці, виконують перерахунок, а потім перевіряють його результати на оптимальність. Якщо рішення не оптимально, то заново обмежують провідний елемент, провідну рядок і ведучий стовпець.
Ознакою оптимальності рішення є наявність у векторі рішень тільки негативних або нульових коефіцієнтів при всіх обмеженнях.
Відповідь записується таким чином:
- Кожному негативного коефіцієнту у векторі рішення ставиться у відповідність нульовий коефіцієнт для відповідної змінної у відповіді.
- Для кожного нульового коефіцієнта у векторі рішення ставиться у відповідність значення вільного члена з рядка, що містить одиницю в стовпці даної змінної.
- Фіктивні змінні у відповіді не враховуються.
Провідним може бути призначений будь-який стовпець, що задовольняє одній з умов:
1) Перший стовпець, що містить позитивний елемент у векторі рішень.
2) Стовпець, що містить найбільший позитивний елемент у рядку рішення.
3) Якщо стовпець задовольняє умові max (C j min b j / a ij) при вирішенні на max, і m in (C j min b j / a ij) при вирішенні завдань на min.
C j - коефіцієнт цільової функції в стовпці j, a ij - коефіцієнт у стовпці j і рядку i.
Рішення завдання
Визначимо максимальне значення цільової функції F (X) = 3500 x 1 +3200 x два +1500 x 3 при наступних умовах обмежень.
4 x 1 + 2 x 2 + 5 x 3 <= 190
5 x 1 + 3 x 2 + 4 x 3 <= 320
7 x 1 + 9 x 2 + 5 x 3 <= 454
Для побудови першого опорного плану систему нерівностей наведемо до системи рівнянь шляхом введення додаткових змінних.
4 x 1 + 2 x 2 + 5 x 3 + 1 x 4 + 0 x 5 + 0 x 6 = 190
5 x 1 + 3 x 2 + 4 x 3 + 0 x 4 + 1 x 5 + 0 x 6 = 320
7 x 1 + 9 x 2 + 5 x 3 + 0 x 4 + 0 x 5 + 1 x 6 = 454
Матриця коефіцієнтів A = a (ij) цієї системи рівнянь має вигляд:
Базисні перемінні це змінні, які входять тільки в одне рівняння системи обмежень і притому з одиничним коефіцієнтом.
Вирішимо систему рівнянь відносно базисних змінних:
x 4, x 5, x 6
Вважаючи, що вільні змінні рівні 0, отримаємо перші опорний план: X 1 = (0,0,0,190,320,454)
Оскільки завдання вирішується на максимум, то провідний стовпець вибирають по максимальному негативному числу і індексному рядку. Усі перетворення проводять до тих пір, поки не вийдуть в індексному рядку позитивні елементи.
Переходимо до основного алгоритму симплекс-методу.
X 1 | X 2 | X 3 | X 4 | X 5 | X 6 | св. чл. |
4 | 2 | 5 | 1 | 0 | 0 | 190 |
5 | 3 | 4 | 0 | 1 | 0 | 320 |
7 | 9 | 5 | 0 | 0 | 1 | 454 |
- 3500 | - 3200 | - 1500 | 0 | 0 | 0 | 0 |
Ітерація № 0
Поточний опорний план неоптімален, так що в індексному рядку знаходяться негативні коефіцієнти
В якості ведучого виберемо стовпець, відповідний змінної x 1, так як найбільший коефіцієнт за модулем.
Обчислимо значення D i по рядках як частка від ділення
і з них виберемо найменше:
Отже, 1-ий рядок є провідною
Дозволяє елемент дорівнює 4 і знаходиться на перетині ведучого шпальти і головною рядки
Формуємо наступну частину симплексного таблиці.
Замість змінної x в план 1 увійде мінлива x 1
Рядок, відповідна змінної x 1 в плані 1, отримана в результаті поділу всіх елементів рядка x 4 плану 0 на дозволяє елемент РЕ = 4
На місці дозволяє елемента в плані 1 отримуємо 1.
В інших клітинах стовпця x 1 плану 1 записуємо нулі.
Таким чином, у новому плані 1 заповнені рядок x 1 і стовпець x 1.
Всі інші елементи нового плану 1, включаючи елементи індексного рядка, визначаються за правилом прямокутника.
Для цього вибираємо зі старого плану чотири числа, які розташовані в вершинах прямокутника і завжди включають дозволяє елемент РЕ.
НЕ = СЕ - (А * В) / РЕ
СТЕ - елемент старого плану, РЕ - дозволяє елемент (4), А і В - елементи старого плану, що утворюють прямокутник з елементами СТЕ і РЕ.
Уявімо розрахунок кожного елемента у вигляді таблиці:
X 1
X 2
X 3
X 4
X 5
X 6
св. чл.
1
1 / 2
5 / 4
1 / 4
0
0
190 / 4
5
3
4
0
1
0
320
7
9
5
0
0
1
454
3500
3200
1500
0
0
0
X 1
X 2
X 3
X 4
X 5
X 6
св. чл.
1
1 / 2
5 / 4
1 / 4
0
0
190 / 4
0
1 / 2
-9 / 4
-5 / 4
1
0
165 / 2
0
11 / 2
-15 / 4
-7 / 4
0
1
243 / 2
0
-1450
2875
875
0
0
Ітерація № 1
Поточний опорний план неоптімален, так що в індексному рядку знаходяться негативні коефіцієнти
В якості ведучого виберемо стовпець, відповідний змінної x 2, так як найбільший коефіцієнт за модулем.
Обчислимо значення D i по рядках як частка від ділення і з них виберемо найменше:
Отже, 3-ий рядок є провідною
Дозволяє елемент дорівнює 5.5 і знаходиться на перетині ведучого шпальти і головною рядки
Формуємо наступну частину симплексного таблиці.
Замість змінної x в план 2 увійде мінлива x 2
Рядок, відповідна змінної x 2 в плані 2, отримана в результаті поділу всіх елементів рядка x 6 плану 1 на дозволяючий елемент РЕ = 5.5
На місці дозволяє елемента в плані 2 отримуємо 1.
В інших клітинах стовпця x 2 плану 2 записуємо нулі.
Таким чином, у новому плані 2 заповнені рядок x 2 і стовпець x 2.
Всі інші елементи нового плану 2, включаючи елементи індексного рядка, визначаються за правилом прямокутника.
Для цього вибираємо зі старого плану чотири числа, які розташовані в вершинах прямокутника і завжди включають дозволяє елемент РЕ.
НЕ = СЕ - (А * В) / РЕ
СТЕ - елемент старого плану, РЕ - дозволяє елемент (5.5), А і В - елементи старого плану, що утворюють прямокутник з елементами СТЕ і РЕ.
Уявімо розрахунок кожного елемента у вигляді таблиці:
Кінець ітерацій: знайдений оптимальний план
Остаточний варіант симплекс-таблиці:
X 1 | X 2 | X 3 | X 4 | X 5 | X 6 | св. чл. |
1 | 0 | 159/100 | 41/100 |
0 | -9/100 | 729/20 | ||||
0 | 0 | -191/100 | -109/100 | 1 | -9/100 | 1429/20 |
0 | 1 | -15/22 | -7/22 | 0 | 9 / 50 | 243/11 |
0 | 0 | 1886.36 | 413.64 | 0 | 263.64 |
Оптимальний план можна записати так:
x 1 = 729/20 = 36.45
x 5 = 1429/20 = 71.45
x 2 = 243/11 = 22.09
F (X) = 3500 * 36.45 + 3200 * 22.09 = 198281.82
Програмна реалізація
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class (TForm)
Label1: TLabel;
Label2: TLabel;
Edit2: TEdit;
Exit: TButton;
Button_Next: TButton;
Edit1: TEdit;
Button_Prev: TButton;
ScrollBox1: TScrollBox;
Conditions: TGroupBox;
Label3: TLabel;
Extrem: TComboBox;
Memo1: TMemo;
procedure ExitClick (Sender: TObject);
procedure Button_NextClick (Sender: TObject);
procedure Button_PrevClick (Sender: TObject);
procedure FormCreate (Sender: TObject);
private
{Private declarations}
public
{Public declarations}
end;
const
mm = 100; nn = 100;
var
Form1: TForm1;
table_changed, done, solve, is_ok, kanon, need_basis, need_i_basis, is_basis, written: boolean;
m, n, y, i_basis, i0, j0, step, iter: integer; {m - елементів, n - обмежень}
pole: array [1 .. nn, 1 .. mm] of TEdit; {поля для введення}
podpis: array [0 .. nn, 0 .. mm] of TLabel; {підпису полів}
znak: array [1 .. nn] of TComboBox; {знаки порівняння обмежень}
matrix: array [1 .. nn, 1 .. mm] of double; {масив для розрахунків}
all_basis: array [1 .. nn] of integer; {номери базисних змінних}
f: text; {файлова змінна для звіту}
tochnost: double;
implementation
{$ R *. dfm}
procedure Init;
{Ініціалізація: введення розмірів системи}
Begin
form1.Button_Prev.Enabled: = false;
form1.Edit1.Enabled: = true;
form1.Edit2.Enabled: = true;
form1.Extrem.Enabled: = true;
form1.ScrollBox1.DestroyComponents; {розчищаємо місце під табличку}
table_changed: = true;
tochnost: = 0.000000001;
assign (f, 'report.htm');
end;
procedure Step1;
{Крок перший: створення таблички і введення значень}
var
i, j: integer;
nadpis: string;
begin
form1.Memo1.ReadOnly: = false;
form1.Memo1.Lines.Clear;
form1.Memo1.ReadOnly: = true;
form1.Extrem.Enabled: = true;
if table _ changed = true then {якщо змінювали кількість ел-тів або обмежень,}
begin {то створюємо нову табличку}
table_changed: = false;
m: = strtoint (form1.Edit1.Text); {зчитуємо кількість змінних}
n: = strtoi
nt (form1.Edit2.Text); {і обмежень}
form1.Edit1.Enabled: = false; {блокуємо поля для їх введення}
form1.Edit2.Enabled: = false;
i: = 0; {використовуємо нульову рядок масиву підписів для заголовків}
for j: = 1 to 3 do {підписуємо що is що}
begin
podpis [i, j]: = TLabel.Create (Form1.ScrollBox1);
podpis [i, j]. parent: = form1.ScrollBox1;
podpis [i, j]. Left: = 5;
podpis [i, j]. Top: = 32 * (j-1); {відстань між написами}
case j of
1: nadpis: = 'Цільова функція: ';
2: nadpis: = 'F (x) =';
3: nadpis: = 'Система обмежень:';
end;
podpis [i, j]. Caption: = nadpis;
end;
i: = n +1; {використовуємо останній рядок масиву полів для цільової ф-ції}
for j: = 1 to m +1 do
begin
pole [i, j]: = TEdit.Create (Form1.ScrollBox1);
pole [i, j]. parent: = form1.ScrollBox1;
pole [i, j]. Height: = 20;
pole [i, j]. Width: = 40;
pole [i, j]. Left: = 80 * (j-1) +30;
pole [i, j]. Top: = 30;
pole [i, j]. Text: = '0 ';
if j <= m then
begin
podpis [i, j]: = TLabel.Create (Form1.ScrollBox1);
podpis [i, j]. parent: = form1.ScrollBox1;
podpis [i, j]. Height: = 20;
podpis [i, j]. Width: = 20;
podpis [i, j]. Left: = pole [i, j]. Left + pole [i, j]. Width +2;
podpis [i, j]. Top: = pole [i, j]. Top +2;
podpis [i, j]. Caption: = 'X [' + inttostr (j )+']';
if j <> m +1 then podpis [i, j]. Caption: = podpis [i, j]. Caption + '+';
{Якщо поле не останнє, то дописуємо плюсик}
end;
end;
for i: = 1 to n do {поля для введення обмежень}
for j: = 1 to m +1 do
begin
pole [i, j]: = TEdit.Create (Form1.ScrollBox1);
pole [i, j]. parent: = form1.ScrollBox1;
pole [i, j]. Height: = 20;
pole [i, j]. Width: = 40;
pole [i, j]. Left: = 80 * (j-1) +5; {відстань між сусідніми + відступ від краю}
pole [i, j]. Top: = 40 * (i-1) +100;
pole [i, j]. Text: = '0 ';
if j <= m then
begin
podpis [i, j]: = TLabel.Create (Form1.ScrollBox1);
podpis [i, j]. parent: = form1.ScrollBox1;
podpis [i, j]. Height: = 20;
podpis [i, j]. Width: = 20;
podpis [i, j]. Left: = pole [i, j]. Left + pole [i, j]. Width +2;
podpis [i, j]. Top: = pole [i, j]. Top +2;
podpis [i, j]. Caption: = 'X [' + inttostr (j )+']';
if j <> m then podpis [i, j]. Caption: = podpis [i, j]. Caption + '+'
{Якщо поле не останнє, то дописуємо плюсик; інакше пишемо знак}
else begin
znak [i]: = TComboBox.Create (Form1.ScrollBox1);
znak [i]. parent: = form1.ScrollBox1;
znak [i]. Height: = 20;
znak [i]. Width: = 40;
znak [i]. Left: = podpis [i, j]. Left + podpis [i, j]. Width +25;
znak [i]. Top: = pole [i, j]. Top;
znak [i]. Items.Insert (0, '>');
znak [i]. Items.Insert (1 ,'>=');
znak [i]. Items.Insert (2, '=');
znak [i]. Items.Insert (3 ,'<=');
znak [i]. Items.Insert (4, '<');
znak [i]. ItemIndex: = 1;
end;
end else pole [i, j]. Left: = pole [i, j]. Left +70; / / поля для правою частини
/ / Обмежень
end;
end else {якщо табличку створювати не треба, то розблокуємо поля}
begin
for i: = 1 to n +1 do
for j: = 1 to m +1 do
begin
pole [i, j]. Enabled: = true;
if i <= n then znak [i]. Enabled: = true;
end;
end;
end;
{/////////////////}
procedure write_system (strok, stolb: integer);
{Записує масив у вигляді рівнянь}
var
i, j: integer;
begin
write (f, '<P> F (x) =');
for j: = 1 to stolb do
begin
write (f, matrix [strok, j]: 0:3);
if j <stolb then
begin
write (f, 'x <sub>', j, '</ sub>');
if (kanon = true) and (j = stolb-1) then write (f, '=') else
if (matrix [strok, j +1]> = 0) then write (f, '+') else write (f, '');
end;
end;
writeln (f, '</ P>');
writeln (f, '<P> При обмеженнях: </ P> <P>');
for i: = 1 to strok-1 do
begin
for j: = 1 to stolb do
BEGIN
write (f, matrix [i, j]: 0:3);
if j <stolb then write (f, 'x <sub>', j, '</ sub>');
if j = stolb-1 then
if kanon = false then write (f, '', znak [i]. text, '')
else write (f, '=');
if (matrix [i, j +1]> = 0) and (j <stolb-1) then write (f ,'+');
end;
writeln (f, '<br>');
end;
writeln (f, '</ P>');
end;
{/////////////////}
procedure zapisat (strok, stolb: integer; v_strok, v_stolb: integer);
{Записує масив у вигляді таблички}
var
i, j: integer;
begin
writeln (f, '<TABLE BORDER BORDERCOLOR=black CELLSPACING=0 CELLPADDING=5>');
for i: = 0 to strok do
begin
writeln (f, '<TR>');
for j: = 1 to stolb +1 do
begin
write (f, '<TD');
if i = 0 then
begin
if (i_basis <> 0) and (j> m + y-i_basis) and (j <= m + y) then
write (f, 'BGCOLOR = yellow')
else
write (f, 'BGCOLOR = green');
end
else
if (i = v_strok) or (j = v_stolb) then write (f, 'BGCOLOR = silver') else
if (i = strok) or (j = stolb) then
if (j <> stolb +1) then write (f, 'BGCOLOR = olive');
write (f, 'align =');
if (i = 0) and (j <stolb) then write(f,'center> X <sub> ', j,' <sub> ') else
if (i = 0) and (j = stolb) then write (f, 'center> св. чл.') else
if (i = 0) and (j = stolb +1) then write (f, 'center> базис') else
if (j = stolb +1) then
if i <> n +1 then write (f, 'center> X <sub>', all_basis [i ],'</ sub> ') else
write (f, 'center>')
else
write (f, 'right>', matrix [i, j]: 1:3);
writeln (f, '</ TD>');
end;
writeln (f, '</ TR>');
end;
writeln (f, '</ TABLE>');
end;
{/////////////////}
procedure findved;
{Шукає провідний елемент}
var
i, j, k: integer;
temp: double;
begin
done: = false;
solve: = false;
is_ok: = true;
temp: = 100000;
i0: = 0;
j0: = 0;
i: = n +1;
for j: = 1 to m + y do
if (i0 = 0) or (j0 = 0) then
if matrix [i, j]> 0 then
begin
j0: = j;
for k: = 1 to n do
if (matrix [k, j]> 0) then
if (matrix [k, m + y +1] / matrix [k, j] <temp) then
begin
temp: = matrix [k, m + y +1] / matrix [k, j];
i0: = k;
end;
end;
if (j0 = 0) and (i0 = 0) then
for j: = 1 to m do
if matrix [n +1, j] = 0 then
for i: = 1 to n do
if (matrix [i, j] <> 0) and (matrix [i, j] <> 1) then
begin
is_ok: = false;
j0: = j;
end;
if is_ok = false then
begin
temp: = 100000;
for k: = 1 to n do
if (matrix [k, j0]> 0) then
if (matrix [k, m + y +1] / matrix [k, j0] <temp) then
begin
temp: = matrix [k, m + y +1] / matrix [k, j0];
i0: = k;
end;
end;
if (j0 = 0) and (i0 = 0) then
begin
writeln (f, '<P> Кінець обчислень </ P> ');
done: = true;
solve: = true;
end
else if (j0 <> 0) and (i0 = 0) then
begin
writeln (f, '<P> Не вдається вирішити систему </ P>');
done: = true;
solve: = false;
end
else
if iter <> 0 then
begin
writeln (f, '<P> <b> Ітерація', iter, '</ b> </ P>');
writeln (f, '<P> Знайдемо провідний елемент: </ P>');
zapisat (n +1, m + y +1, i0, j0);
writeln (f, '<P> Ведучий стовпчик:', j0, '<br> Провідна рядок:', i0, '</ P>');
write (f, '<P> У стрічці', i0, ': базис');
writeln (f, 'X <sub>', all_basis [i0 ],'</ sub> замінюємо на X <sub> ', j0,' </ sub> </ P> ');
all_basis [i0]: = j0;
end;
end;
{/////////////////}
procedure okr;
{Округлює дрібні похибки}
var
i, j: integer;
begin
for i: = 1 to n +1 do
for j: = 1 to m + y +1 do
if abs (matrix [i, j]-round (matrix [i, j])) <tochnost then
matrix [i, j]: = round (matrix [i, j]);
end;
{/////////////////}
procedure preobr;
{Перетворює масив щодо ведучого елемента}
var
i, j, k, l, t: integer;
temp: double;
begin
if done = false then
begin
write (f, '<P> Перерахунок: </ P>');
temp: = matrix [i0, j0];
for j: = 1 to m + y +1 do matrix [i0, j]: = matrix [i0, j] / temp;
for i: = 1 to n +1 do
begin
temp: = matrix [i, j0];
for j: = 1 to m + y +1 do
if (i <> i0) then
matrix [i, j]: = matrix [i, j]-matrix [i0, j] * temp;
end;
okr;
zapisat (n +1, m + y +1, -1, -1);
{///////////////////////// Прибираємо штучний базис ///////////////////// }
if i _ basis> 0 then {якщо він є}
begin
t: = 0;
for j: = m + y - i _ basis +1 to m + y do {від першого ісскусственного елемеента до кінця}
begin
need _ i _ basis: = false; {припускаємо, що елемент не потрібен (*)}
for i: = 1 to n do {переглядаємо стовпець}
if all _ basis [i] = j then {і якщо елемент у базисі}
need _ i _ basis: = true; {тоді він все-таки потрібен}
if need_i_basis = false then t: = j;
{Якщо наші припущення (*) підтвердилися, то запам'ятаємо цей елемент}
end;
if t <> 0 then
begin
for k: = 1 to n +1 do {у всіх рядках}
begin
for l: = t to m + y do {від поточного стовпця до останнього}
matrix [k, l]: = matrix [k, l +1]; {замінюємо елемент на сусідній}
matrix [k, m + y +1]: = 0; {а останній прибираємо}
end;
{Стовпець знищений! треба це запам'ятати}
y: = y-1;
i_basis: = i_basis-1;
if i _ basis> 0 then {якщо залишилися ще штучні змінні,}
for l: = m + y - i _ basis +1 to m + y do {то від першої з них до останньої}
for i: = 1 to n do {переглядаємо рядка у стовпці}
if matrix [i, l] = 1 then all_basis [i]: = l; {туди, де 1, заносимо в базис}
writeln (f, '<P> Штучна мінлива виключена з базису <br>');
writeln (f, 'і може бути вилучена з таблиці.');
writeln (f, '</ P>');
zapisat (n +1, m + y +1, -1, -1);
end;
end;
{/////////////// Закінчили прибирати штучний базис ////////////////////}
end;
end;
{/////////////////}
procedure otvet;
{Виводить відповідь}
var
i, j: integer;
begin
writeln (f, '<P> <b> ВІДПОВІДЬ: </ b> </ P>');
form1.Memo1.ReadOnly: = false;
form1.Memo1.Lines.Clear;
form1.Memo1.Lines.Add ('ВІДПОВІДЬ:');
form1.Memo1.Lines.Add ('');
if (solve = true) and (i_basis = 0) then
write (f, 'F (');
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 'F (';
if form1.Extrem.ItemIndex = 0 then
begin
write (f, 'max) =' ,0-matrix [n +1, m + y +1]: 0:3);
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 'max) =';
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + floattostr (0-matrix [n +1, m + y +1]);
end
else
begin
write (f, 'min) =', matrix [n +1, m + y +1]: 0:3);
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 'min) =';
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + floattostr (matrix [n +1, m + y +1]);
end;
writeln (f, '<br> при значеннях: <br>');
form1.Memo1.Lines.Add ('');
form1.Memo1.Lines.Add ('');
form 1. Memo 1. Lines. Add ('при значеннях:');
form1.Memo1.Lines.Add ('');
for j: = 1 to m do
begin
writeln (f, 'x <sub>', j, '</ sub> =');
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 'X [';
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + inttostr (j);
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + '] =';
written: = false;
for i: = 1 to n do
if all_basis [i] = j then
begin
writeln (f, matrix [i, m + y +1]: 0:3, '<br>');
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + floattostr (matrix [i, m + y +1]);
form1.Memo1.Lines.Add ('');
form1.Memo1.Lines.Add ('');
written: = true;
end;
if written = false then
begin
writeln (f, '0 .000 <br> ');
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 0 ";
form1.Memo1.Lines.Add ('');
form1.Memo1.Lines.Add ('');
end;
end;
end else
begin
writeln (f, '<P> Рішення НЕ знайдено. (</ P> ');
form1.Memo1.Lines.Text: = form1.Memo1.Lines.Text + 'Рішення НЕ знайдено. ';
end;
form1.Memo1.ReadOnly: = true;
end;
{/////////////////}
procedure Step2;
{Крок другий: вирішення завдання і формування звіту}
var
i, j: integer;
k: integer;
begin
for i: = 1 to n +1 do
for j: = 1 to m +1 do
begin
matrix [i, j]: = strtofloat (pole [i, j]. Text); {Вводимо значення в масив}
pole [i, j]. Enabled: = false; {Блокуємо поля}
if i <= n then znak [i]. Enabled: = false; {блокуємо знаки}
end;
form1.Extrem.Enabled: = false;
{///////////////////////////////////////////////// ///////////////////////////}
{Маємо матрицю [n +1, m +1]}
rewrite (f);
writeln (f, '<HTML>');
writeln (f, '<HEAD>');
writeln (f, '<TITLE> Звіт </ TITLE>');
writeln (f, '</ HEAD>');
writeln (f, '<BODY>');
writeln (f, '<H1> Звіт </ H1>');
write (f, '<P> <b> Необхідно');
if form1.Extrem.ItemIndex = 0 then write (f, 'макс') else write (f, 'хв');
writeln (f, 'імізіровать цільову функцію: </ b> </ P>');
kanon: = false; {ще не в канонічній формі}
write_system (n +1, m +1); {Виведемо її до звіту}
{Приведемо її до канонічного вигляду}
writeln (f, '<P> <b> Наведемо до канонічного вигляду: </ b> </ P>');
y: = 0; {кількість додаткових змінних}
need_basis: = false;
for i: = 1 to n do
if znak [i]. ItemIndex <> 2 then {якщо обмеження не є рівністю}
begin
y: = y +1; {вводимо додаткову змінну, для цього:}
for k: = 1 to n +1 do begin {у всіх обмеженнях і в ЦФ}
{Перед правою частиною додаємо стовпець}
matrix [k, m + y +1]: = matrix [k, m + y];
matrix [k, m + y]: = 0; {складається з нулів}
end;
{А в поточному обмеження, якщо знак був> або> =}
if (znak [i]. ItemIndex = 0) or (znak [i]. ItemIndex = 1) then
begin
matrix [i, m + y]: =- 1; {записуємо -1}
need_basis: = true;
end
else {інакше, тобто у разі <або <=}
matrix [i, m + y]: = 1; {записуємо 1}
end
else need_basis: = true;
{ЦФ прирівнюється до нуля, а вільний член переноситься в праву частину:}
matrix [n +1, m + y +1]: = 0-matrix [n +1, m + y +1];
{Праві частини обмежень повинні бути ненегативні, перевіримо це:}
for i: = 1 to n do {для всіх обмежень}
if matrix [i, m + y +1] <0 then {якщо права частина негативна,}
{То забираємо всю рядок від нуля}
for j: = 1 to m + y +1 do matrix [i, j]: = (0-matrix [i, j]);
kanon: = true; {система приведена до канонічного вигляду}
{Виведемо її до звіту}
write_system (n +1, m + y +1);
{Якщо ф-ція на мінімум, то потрібно поміняти знаки в останньому рядку}
if form1.Extrem.ItemIndex = 1 then
for j: = 1 to m + y +1 do matrix [n +1, j]: = 0-matrix [n +1, j];
{///////////////////////////////////////////////// ///////////////////////////}
{////////////////////////// Тут треба ввести базис /////////////////// ////////}
i_basis: = 0;
for i: = 1 to n do {то у всіх обмеженнях}
begin
is_basis: = false;
for j: = 1 to m + y do
if (matrix [i, j] = 1) then
if (is_basis = false) then
begin
all_basis [i]: = j;
is_basis: = true;
for k: = 1 to n do
if k <> i then
if (matrix [k, j] <> 0) then
if (is_basis = true) then
begin
is_basis: = false;
all_basis [i]: = 0;
end;
end;
if is_basis = false then
begin
i_basis: = i_basis +1;
y: = y +1;
for k: = 1 to n +1 do
begin {у всіх обмеженнях і в ЦФ}
{Перед правою частиною додаємо стовпець}
matrix [k, m + y +1]: = matrix [k, m + y];
matrix [k, m + y]: = 0; {складається з нулів}
end;
matrix [i, m + y]: = 1;
all_basis [i]: = m + y;
end;
end;
{//////////////// Закінчили введення штучного базису //////////////////////}
{///////////////////////////////////////////////// ///////////////////////////}
{///////////////////////////////////////////////// ///////////////////////////}
{//////////////// Тепер треба від нього позбавитися //////////////////////////// }
if i _ basis> 0 then
begin
write (f, '<H 2> Необхідно ввести штучний базис </ H 2>');
zapisat (n +1, m + y +1, -1, -1);
writeln (f, '<P> Штучний базис введений. <br>');
writeln (f, 'Позбувшись від нього, отримаємо перше допустиме рішення </ P>');
iter: = 0;
repeat
inc (iter);
findved;
preobr;
until (i_basis = 0) or (iter = 20) or (done = true);
if i_basis = 0 then
begin
writeln (f, '<P> Штучний базис виведений повністю. <br>');
writeln (f, 'Отримано першу допустиме рішення! </ P>');
end
else
begin
writeln (f, '<P> Не вдалося вивести штучний базис. <br>');
writeln (f, 'Рішення не знайдено. </ P>');
end;
end;
{//////////////////////// Спроби позбавлення закінчені ////////////////////// / /}
{///////////////////////////////////////////////// ///////////////////////////}
{/////////////////////////////// SIMPLEX START //////////////// /////////////}
if i_basis = 0 then
begin
iter: = 0;
findved;
if done = false then
begin
writeln (f, '<H2> Застосовуємо симплекс метод </ H2>');
repeat
inc (iter);
findved;
preobr;
until (done = true) or (iter = 20);
end;
end;
otvet;
{/////////////////////////////// SIMPLEX END //////////////// ///////////////}
writeln (f, '</ BODY>');
writeln (f, '</ HTML>');
CloseFile (f);
{///////////////////////////////////////////////// ///////////////////////////}
end;
{///////////////////////////////////////////////// ///////////////////////////}
{///////// Все, що нижче, відноситься до переходів між кроками ////////////////}
{///////////////////////////////////////////////// ///////////////////////////}
procedure TForm1.ExitClick (Sender: TObject);
begin
Close ();
end;
procedure TForm1.Button_NextClick (Sender: TObject);
begin
step: = step +1;
Form1.Button_Prev.Enabled: = true;
case step of
1: Step1;
2: begin
Step2;
Form1.Button_Next.Enabled: = false;
end;
else step: = step-1;
end;
form1.Caption: = 'Симплекс метод - крок' + inttostr (step);
end;
procedure TForm1.Button_PrevClick (Sender: TObject);
begin
step: = step-1;
Form1.Button_Next.Enabled: = true;
case step of
0: begin
Init;
Form1.Button_Prev.Enabled: = false;
end;
1: Step1;
else step: = step +1;
end;
form1.Caption: = 'Симплекс метод - крок' + inttostr (step);
end;
procedure TForm1.FormCreate (Sender: TObject);
begin
Init;
end;
Висновок
У цій роботі було розглянуто рішення задач лінійного програмування симплекс методом. Задача була вирішена симплекс методом, так само завдання було вирішено графічно (побудований графік). Для представленої задачі була складена програма на мові Delphi, програма знаходить значення цільової функції за умови максимізації значення.
Таким чином, обчислювальна техніка в даний час знаходить широке застосування, як у загальній математики, так і в одному з її розділів - математичних методах.
Список використаної літератури
1. Зайченко Ю.П., Шумилова С.А. Дослідження операцій.
2. Ліщенко «Лінійне і нелінійне програмування», М. 2003
3. О.М. Карасьов, Н.Ш. Кремер, Т.М. Савельєва «Математичні методи в економіці», М.2000
4. Орлов О.І. Теорія прийняття рішень. Навчальний посібник. - М.: Видавництво "Март", 2004
5. Інтернет