Зміст
Введення
1. Постановка і аналіз завдання
2. Рішення завдання
3. Опис алгоритму
4. Опис програми
5. Контрольний приклад
Висновок
Текст програми
Література
1. Введення
Зазвичай при виробництві виробів матеріал надходить у вигляді рулонів, смуг, прямокутних листів, стержнів і т. д. Вступник матеріал розкроюється на частини заданих розмірів і певної конфігурації, що представляють собою в одних випадках заготовки, в інших - готові деталі. До завдань розкрою, відносяться і завдання щільного розміщення сукупності предметів на заданих ділянках.
Завдання раціонального розкрою описуються схожими математичними моделями. Істотна відмінність цих моделей визначається головним чином двома факторами:
1) конфігурацією одержуваних при розкрої заготовок;
2) обсягом продукції, що випускається.
Завдання розкрою, визначаються першим чинником, поділяють на два класи. До першого класу належать завдання фігурного розкрою, до другого - завдання нефігурного розкрою. При фігурному розкрої матеріал розкроюється на заготовки самих різних конфігурацій. До класу задач нефігурного розкрою належать завдання лінійного і прямокутного розкрою. У першому випадку матеріал розкроюють на заготовки різної довжини, для яких задається тільки один лінійний розмір. У другому випадку отримують заготовки прямокутної форми, для яких задаються два розміри.
Завдання розкрою, зумовлені другим фактором, також поділяють на два класи: задачі розкрою в умовах масового (великосерійного) випуску виробів і завдання розкрою в умовах одиничного (дрібносерійного) виробництва. До обох класів можуть належати як завдання фігурного, так і завдання нефігурного розкрою. Завдання розкрою в умовах масового виробництва описуються безперервними моделями лінійного програмування, а в умовах одиничного виробництва - цілочисельними. У зв'язку з цим задачі розкрою в зазначених умовах часто називають відповідно безперервними і цілочисельними.
Завдання раціонального розкрою в умовах масового виробництва відносяться до класу задач лінійного програмування, з неявно заданими стовпцями (способами розкрою). При вирішенні таких завдань методами лінійного програмування виникає необхідність у генеруванні розкриємо на кожному кроці процесу. Нижче розглянуто задачу генерування лінійних розкрою.
1. Постановка і аналіз завдання
Вирішити завдання гільйотинного розкрою матеріалу (довгомірного прокату) з максимальним прибутком: шматок матеріалу довжиною L розкроюється на заготовки m найменувань, для кожної заготівлі з номером i = відомі її довжина l i і оцінка з i. Потрібно знайти розкрій з максимальною оцінкою одержуваного набору заготовок.
Задача оптимального розкрою довгомірного прокату носить різний характер в залежності від типу виробництва. Наприклад, для великосерійного виробництва характерні наступні завдання: прагнення отримати значне число заготовок однакової довжини, мінімізувати залишок, отримати максимальний прибуток від розкрою і т.д. У цій роботі буде розглянуто рішення задачі оптимального розкрою матеріалу з максимальним прибутком методом динамічного програмування з використанням так званої "сітковим методом", при якому виникає необхідність генерування розкриємо на кожному кроці процесу.
2. Рішення завдання
Припустимо, що шматок матеріалу довжиною L розкроюється на заготовки m найменувань. Для кожної заготівлі з номером i = відомі її довжина l i і оцінка з i. Потрібно знайти розкрій з максимальною оцінкою одержуваного набору заготовок.
Розкрій може містити будь-яке число кожної із заготовок. Тоді набір заготовок характеризується m-вимірним вектором
X = (x 1, x 2, ..., x m), (1)
Елементи якого являють собою цілі невід'ємні компоненти, що вказують на число заготовок кожного виду. При цьому потрібно максимізувати сумарну оцінку
(2)
набору заготовок (1) за єдиної лінійному обмеження
. (3)
Генерування розкрою будемо розглядати як багатокроковий циклічний процес, що складається з послідовного вибору окремих заголовок.
Для вирішення поставленого завдання розглянемо функцію
(4)
x Î X l
де через X i позначено множину невід'ємних векторів х, що відповідають розкрою, в яких загальна довжина заготовок не перевершує довжини l. Нехай l 0 = min l i, де i = 1 ... m.
Тоді при всіх l Î [0, l 0] відповідні множини X l складаються з одного нульового елемента і, отже, f (l) = 0 для всіх таких l. Для l Î [0, L 0], справедливі наступні рекурентні співвідношення:
, (5)
i Î I l
де через I l позначено безліч тих i, при яких l i £ l.
Спираючись на рекурентні співвідношення (5), можна для вирішення завдання запропонувати простий чисельний метод, який представляє собою перебір всіх допустимих розкрою. Реалізація всього процесу грунтується на двох етапах:
Перший етап
На першому етапі здійснюється так званий прямий хід: за формулами (5) для всіх l = послідовно обчислюються функції f (l) і при цьому фіксуються індекси i (l), при яких досягається максимум у виразі (5). Отримана при цьому інформація l, f (l) і i (l) запам'ятовується і підрядник записується в таблицю:
l | l 0 | l 0 + 1 | l 0 + 2 | ... | L |
f (l) | f (l 0) | f (l 0 + 1) | f (l 0 + 2) | ... | f (L) |
i (l) | i (l 0) | i (l 0 + 1) | i (l 0 + 2) | ... | i (L) |
Другий етап
На другому етапі здійснюється так званий зворотний хід: для отримання шуканого вектора х (1), для якого виконується рівність m (x) = f (L), в розкрій в першу чергу включаються заготовка з номером i (l 1), де l 1 = L, і підраховується значення l 2 = l 1 - l i (l 1).
Якщо l 2 ³ l 0, то в розкрій включається заготовка з номером i (l 2) і підраховується значення l 3 = l 2 - l i (l 2) і т.д. Так як при кожному k ³ 1 очевидно, що l k +1 £ l k - l 0, то через кінцеве число описаних кроків виявиться, що l k +1 <l 0. На цьому генерування шуканого розкрою закінчується і виводиться результат.
3. Опис алгоритму
1. Визначається поточне значення довжини розкрою l від мінімальної довжини деталі до довжини матеріалу.
2. Обчислюється максимальний індекс (номер) деталі, додавання якої можливо.
3. Якщо немає деталей, які можна додати в розкрій, то перевіряється не досягнуть чи максимум ціни розкрою для поточного значення довжини розкрою l.
Якщо максимум досягнуто, то він запам'ятовується. Остання додана деталь видаляється з розкрою і додається наступна (п. 4). Якщо немає деталей які можна додати в розкрій, відбувається вихід з циклу.
4. Запам'ятовується поточний розкрій. Довжина розкрою зменшується на довжину деталі. Ціна розкрою збільшується на ціну деталі. Визначаються деталі, додавання яких до розкрій можливо (п. 2).
5. Береться початкова довжина розкрою, рівна довжині матеріалу. Береться деталь, на якій було досягнуто максимум для даної довжини матеріалу. З довжини матеріалу віднімається довжина деталі, до вартості розкрою додається ціна деталі. П.5 повторюється, поки є деталі, додавання яких до розкрою не перевищить довжини матеріалу.
6. Знаючи кількість деталей для кожного їх виду, складових раціональний розкрій, формується шуканий вектор х.
/ / Процедура обчислення раціонального розкрою
procedure searchRationalCut (
materialLength: integer;
detailAmount: integer;
var details: array of TDetail;
var x: array of integer);
var
l0, l, i: integer;
currCut: TCutRecord;
maxCut: TCutRecord;
cutRecords: array [0 .. MAX_CUTRECORD_AMOUNT-1] of TCutRecord;
cutRecords1: array [1 .. MAX_CUTRECORD_AMOUNT] of TCutRecord;
i1, j1: integer;
begin
l0: = details [0]. l;
for l: = l0 to materialLength do
begin
currCut.l: = l;
currCut.c: = 0;
currCut.i: = 0;
currCut.max_i: =- 1;
maxCut.l: = 0;
maxCut.c: = 0;
maxCut.i: = 0;
maxCut.max_i: = 0;
j1: = 0;
while true do
begin
if currCut.max_i =- 1 then
begin
for i1: = 0 to detailAmount-1 do
begin
if details [i1]. l <= currCut.l then
begin
currCut.max_i: = i1;
currCut.i: = 0;
end;
end;
end;
if (currCut.max_i =- 1) or (currCut.i> currCut.max_i) then
begin
if j1 <> 0 then
begin
if currCut.c> maxCut.c then
begin
maxCut: = currCut;
end;
currCut: = cutRecords1 [j1];
j1: = j1-1;
currCut.i: = currCut.i +1;
end
else
begin
break;
end;
end
else
begin
if (currCut.l> = l0) and (currCut.l <l) then
begin
if cutRecords [currCut.l]. c + currCut.c> maxCut.c then
begin
maxCut: = cutRecords [currCut.l];
maxCut.c: = maxCut.c + currCut.c;
end;
currCut.i: = currCut.i +1;
continue;
end;
j1: = j1 +1;
cutRecords1 [j1]: = currCut;
currCut.l: = currCut.l-details [currCut.i]. l;
currCut.c: = currCut.c + details [currCut.i]. c;
currCut.max_i: =- 1;
end;
end;
cutRecords [l]: = maxCut;
cutRecords [l]. l: = l;
end;
for i: = 0 to detailAmount-1 do
begin
x [i]: = 0;
end;
l: = materialLength;
while l> = details [0]. l do
begin
x [cutRecords [l]. i]: = x [cutRecords [l]. i] +1;
l: = l-details [cutRecords [l]. i]. l;
end;
end;
4. Опис програми
Вид головного вікна програми наведено на малюнку:
Після запуску програми користувачеві пропонується ввести довжину матеріалу і кількість типів деталей, потім потрібно заповнити поля таблиці з довжиною і вартістю кожної деталі.
Після введення даних для вирішення потрібно натиснути кнопку "Обчислити", програма видасть результат у вигляді таблиці з оптимальними значеннями кількості типів деталей. Також виводиться загальна оцінка розкрою, залишок матеріалу і наочна карта розкрою прокату в графічній формі. Білі частини розкрою позначають типи деталей, червоні лінії - лінії відрізу матеріалу. У випадку залишку, відповідна частина розкрою відображається сірим кольором:
5. Контрольний приклад
Нехай у задачі генерування лінійного розкрою задані наступні параметри: довжина прокату L = 40, кількість типів деталей m = 4, а значення довжин l i і вартості c i кожної деталі наведені в таблиці:
i | 1 | 2 | 3 | 4 |
l i | 7 | 11 | 13 | 17 |
c i | 9 | 14 | 16 | 22 |
Вирішуємо задачу сітковим методом: спочатку виконуємо прямий хід. Вибираємо початкове значення довжини розкрою, рівне мінімальній довжині деталі: l 0 = min l i = 7 і послідовно "крокуємо" до кінця прокату, тобто 40.
Щоб знайти максимальну вартість на кожному кроці, ми перебираємо всі деталі, які можуть поміститися в поточний розкрій, починаючи з мінімальної по довжині. Для підрахунку вартості розкрою на поточному кроці ми віднімаємо довжину черговий обраної деталі з поточного розкрою і по таблиці знаходимо розкрій з довжиною, рівній отриманому залишку і підсумовуємо його оцінку з оцінкою обраної деталі. З обчислених оцінок вибираємо максимальну і заносимо її в таблицю, разом з номером деталі, при якій ця оцінка була отримана.
Далі в таблиці наведено результати першого етапу (прямого ходу) процесу:
l | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
f (l) | 9 | 9 | 9 | 9 | 14 | 14 | 16 | 18 | 18 | 18 | 22 | 23 | 23 | 25 | 27 | 28 | 28 |
i (l) | 1 | 1 | 1 | 1 | 2 | 2 | 3 | 1 | 1 | 1 | 4 | 1 | 1 | 1 | 1 | 2 | 2 |
l | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
f (l) | 31 | 32 | 32 | 34 | 36 | 37 | 38 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 49 | 50 | 51 |
i (l) | 1 | 1 | 1 | 1 | 1 | 1 | 3 | 1 | 1 | 2 | 4 | 1 | 1 | 1 |
1 | 1 | 1 |
Тут і далі i (l) - номер деталі, якій відповідає максимальна оцінка розкрою (сума вартості всіх деталей, що входять в розкрій) f (l) на кроці l.
Розглянемо більш детально послідовне заповнення таблиці на прикладі кроків
l = 7 ... 14, 22.
1) l = 7
Вибираємо першу деталь: i = 1. Довжина деталі 7, оцінка 9.
Обчислюємо залишок від розкрою: 7 - 7 = 0. Оскільки залишок нульовий, то деталей, які можна додати в розкрій, немає. Отже, максимальна оцінка поточного розкрою дорівнює f = 9. Заносимо в таблицю значення i (7) = 1, f (7) = 9 і переходимо до наступного кроку розкрою.
2) l = 8
Знову беремо першу деталь: i = 1. Довжина деталі 7, оцінка 9.
Залишок: 8 - 7 = 1. Так як деталей з такою довжиною немає, максимальна оцінка розкрою f = 9. Заносимо в таблицю i (8) = 1, f (8) = 9.
3) l = 9
i = 1, залишок 9 - 7 = 2, f = 9.
Заносимо в таблицю i (9) = 1, f (9) = 9.
4) l = 10
i = 1, залишок 10 - 7 = 3, f = 9.
Заносимо в таблицю i (10) = 1, f (10) = 9.
5) l = 11
i = 1, залишок 11 - 7 = 4, f = 9.
Враховуючи, що в поточний розкрій також вміститься деталь i = 2 c довжиною 11, отримаємо: i = 2, залишок 11 - 11 = 0, f = 14.
Порівняємо оцінки розкрою. Виберемо максимальну оцінку (f = 14) і відповідну їй деталь (i = 2).
Заносимо в таблицю i (11) = 2, f (11) = 14.
6) l = 12
i = 1, залишок 12 - 7 = 5, f = 9.
i = 2, залишок 12 - 11 = 1, f = 14 (максимум)
Заносимо в таблицю i (12) = 2, f (12) = 14.
7) l = 13
i = 1, залишок 13 - 7 = 6, f = 9.
i = 2, залишок 13 - 11 = 2, f = 14.
i = 3, залишок 13 - 13 = 0, f = 16 (максимум)
Заносимо в таблицю i (13) = 3, f (13) = 16.
8) l = 14
i = 1, залишок 14 - 7 = 7.
Якщо ми бачимо, що довжина залишку розкрою більше або дорівнює початковому значенням довжини розкрою (l 0 = 7), тобто в залишок може поміститися яка-небудь деталь (в даному випадку з індексом i = 1), з таблиці зчитуємо значення оцінки розкрою f (i) при i, рівному значенням залишку: f (7) = 9, тоді сумарна оцінка розкрою f = f (7) + 9 = 9 + 9 = 18 (максимум)
i = 2, залишок 14 - 11 = 3, f = 14.
i = 3, залишок 14 - 13 = 1, f = 16.
Заносимо в таблицю i (14) = 1, f (14) = 18.
... 16) l = 22
i = 1, залишок 22 - 7 = 15, f (15) = 18, f = 18 + 9 = 27.
i = 2, залишок 22 - 11 = 11, f (11) = 14, f = 14 + 14 = 28 (максимум)
i = 3, залишок 22 - 13 = 9, f (9) = 9, f = 9 + 16 = 25.
i = 4, залишок 22 - 17 = 5, f = 22.
Заносимо в таблицю i (22) = 2, f (22) = 28. і т.д., поки не досягнуть кінець прокату.
Виконуємо зворотний хід (починаємо рухатися з кінця таблиці):
1) l = 40
З таблиці отримуємо індекс деталі, доданої в поточний розкрій: i (40) = 1.
Знаходимо довжину деталі з отриманим індексом: l 1 = 7.
Обчислюємо залишок розкрою: 40 - 7 = 33. Цей залишок використовуємо для наступного кроку зворотного ходу.
2) l = 33
Індекс деталі: i (33) = 2.
Довжина деталі: l 2 = 11.
Залишок розкрою: 33 - 11 = 22.
3) l = 22
Індекс деталі: i (22) = 2.
Довжина деталі: l 2 = 11.
Залишок розкрою: 22 - 11 = 11.
4) l = 11
Індекс деталі: i (11) = 2.
Довжина деталі: l 2 = 11.
Залишок розкрою: 11 - 11 = 0. Зворотний хід закінчений.
Тепер підраховуємо кількість деталей кожного типу, які ми отримали при зворотному ході. Деталь з індексом i = 1 зустрілася 1 раз, деталь з індексом i = 2 зустрілася 3 рази.
Таким чином, шуканий оптимальний розкрій характеризується наступним чотиривимірним вектором x = (1; 3; 0; 0).
У вищенаведеній таблиці з результатами прямого ходу виділені номери заготовок, які при зворотному ході послідовно включалися в оптимальний розкрій.
Результат роботи програми (перевірка алгоритму):
Вихідні дані
Довжина прокату: 40
Кількість типів деталей: 4
Довжина деталі № 1 ....: 7 Ціна деталі № 1 ....: 9
Довжина деталі № 2 ....: 11 Ціна деталі № 2 ....: 14
Довжина деталі № 3 ....: 13 Ціна деталі № 3 ....: 16
Довжина деталі № 4 ....: 17 Ціна деталі № 4 ....: 22
Результат
Оптимальна кількість деталей кожного типу:
Деталь № 1 ....: 1 шт.
Деталь № 2 ....: 3 шт.
Деталь № 3 ....: 0 шт.
Деталь № 4 ....: 0 шт.
Оцінка розкрою: 51 грошових одиниць
Залишок матеріалу: 0
Результати ручного і машинного обчислень збігаються, що говорить про працездатність розробленого алгоритму для ЕОМ.
Висновок
У даній роботі поставлена задача була вирішена за допомогою сіткового методу. Як показала проведена робота, цей метод ефективний і простий для програмної реалізації на ЕОМ. Результат, отриманий за допомогою цього методу, є оптимальним. У ньому реалізується цілеспрямований перебір за кінцеве число кроків, в результаті чого знаходиться раціональний розкрій з максимумом прибутку.
У роботі були зроблені ручні обчислення і по них перевірено роботу запрограмованого алгоритму на ЕОМ. Розроблена програма і сітковий метод оптимізації розкрою досить універсальні. Вони можуть застосовуватися в різних галузях промисловості при масовому виробництві, при цьому в алгоритм слід вносити корективи, пов'язані з обліком технології виробництва та обладнання.
Текст програми
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, ComCtrls, ExtCtrls;
type
/ / Деталь
TDetail = record
l: integer; / / довжина
c: integer; / / ціна
end;
/ / Запис розкрою
TCutRecord = record
l: integer; / / довжина
c: integer; / / ціна
i: integer; / / індекс деталі
max_i: integer; / / максимальний індекс деталі для поточної довжини матеріалу
end;
TForm_Main = class (TForm)
GroupBox1: TGroupBox;
Edit_MaterialLength: TEdit;
Label_MaterialLength: TLabel;
UpDown_MaterialLength: TUpDown;
Label_DetailAmount: TLabel;
UpDown_DetailAmount: TUpDown;
Edit_DetailAmount: TEdit;
StringGrid_In: TStringGrid;
GroupBox2: TGroupBox;
StringGrid_Out1: TStringGrid;
Button_Calculate: TButton;
Button_Exit: TButton;
GroupBox3: TGroupBox;
Image_Cut: TImage;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
procedure Button_ExitClick (Sender: TObject);
procedure Edit_DetailAmountChange (Sender: TObject);
procedure FormCreate (Sender: TObject);
procedure Edit_MaterialLengthChange (Sender: TObject);
procedure Button_CalculateClick (Sender: TObject);
procedure Button1Click (Sender: TObject);
private
{Private declarations}
public
{Public declarations}
end;
const
MAX_DETAIL_AMOUNT = 10; / / максимальна к - ть деталей
MAX_CUTRECORD_AMOUNT = 10000; / / максимальна к - ть записів розкрою
MAX_MATERIAL_LENGTH = 10000; / / максимальна довжина матеріалу
var
Form_Main: TForm_Main;
materialLength: integer; / / довжина матеріалу
detailAmount: integer; / / к - ть деталей
details: array [1 .. MAX_DETAIL_AMOUNT] of TDetail; / / деталі
x: array [1 .. MAX_DETAIL_AMOUNT] of integer; / / результат
implementation
uses Unit2;
{$ R *. DFM}
/ / Процедура обчислення раціонального розкрою
procedure searchRationalCut (
materialLength: integer;
detailAmount: integer;
var details: array of TDetail;
var x: array of integer);
var
l0, l, i: integer;
currCut: TCutRecord;
maxCut: TCutRecord;
cutRecords: array [0 .. MAX_CUTRECORD_AMOUNT-1] of TCutRecord;
cutRecords1: array [1 .. MAX_CUTRECORD_AMOUNT] of TCutRecord;
i1, j1: integer;
begin
l0: = details [0]. l;
for l: = l0 to materialLength do
begin
currCut.l: = l;
currCut.c: = 0;
currCut.i: = 0;
currCut.max_i: =- 1;
maxCut.l: = 0;
maxCut.c: = 0;
maxCut.i: = 0;
maxCut.max_i: = 0;
j1: = 0;
while true do
begin
if currCut.max_i =- 1 then
begin
for i1: = 0 to detailAmount-1 do
begin
if details [i1]. l <= currCut.l then
begin
currCut.max_i: = i1;
currCut.i: = 0;
end;
end;
end;
if (currCut.max_i =- 1) or (currCut.i> currCut.max_i) then
begin
if j1 <> 0 then
begin
if currCut.c> maxCut.c then
begin
maxCut: = currCut;
end;
currCut: = cutRecords1 [j1];
j1: = j1-1;
currCut.i: = currCut.i +1;
end
else
begin
break;
end;
end
else
begin
if (currCut.l> = l0) and (currCut.l <l) then
begin
if cutRecords [currCut.l]. c + currCut.c> maxCut.c then
begin
maxCut: = cutRecords [currCut.l];
maxCut.c: = maxCut.c + currCut.c;
end;
currCut.i: = currCut.i +1;
continue;
end;
j1: = j1 +1;
cutRecords1 [j1]: = currCut;
currCut.l: = currCut.l-details [currCut.i]. l;
currCut.c: = currCut.c + details [currCut.i]. c;
currCut.max_i: =- 1;
end;
end;
cutRecords [l]: = maxCut;
cutRecords [l]. l: = l;
end;
for i: = 0 to detailAmount-1 do
begin
x [i]: = 0;
end;
l: = materialLength;
while l> = details [0]. l do
begin
x [cutRecords [l]. i]: = x [cutRecords [l]. i] +1;
l: = l-details [cutRecords [l]. i]. l;
end;
end;
/ / Введення даних користувача з таблиці
procedure updateData;
var
i: integer;
begin
materialLength: = strToInt (Form_Main.Edit_MaterialLength.Text);
detailAmount: = strToInt (Form_Main.Edit_DetailAmount.Text);
for i: = 1 to detailAmount do
begin
details [i]. l: = strToInt (Form_Main.StringGrid_In.Cells [1, i]);
details [i]. c: = strToInt (Form_Main.StringGrid_In.Cells [2, i]);
end;
end;
/ / Графічне відображення раціонального розкрою
procedure drawRationalCut (
image: TImage;
materialLength: integer;
detailAmount: integer;
details: array of TDetail;
x: array of integer);
var
i, j: integer;
sum: integer;
k_x: real;
curr_x: integer;
curr_x_scr: real;
begin
sum: = 0;
for i: = 0 to detailAmount-1 do
begin
sum: = sum + x [i] * details [i]. l;
end;
k_x: = image.width / materialLength;
with image.Canvas do
begin
brush.Style: = bsSolid;
brush.Color: = clBtnFace;
fillRect (rect (0, 0, image.width, image.height));
brush.Color: = clGray;
pen.Color: = clGray;
rectangle (trunc (k_x * sum), 0, trunc (k_x * materialLength), 50);
brush.Color: = clWhite;
pen.Color: = clGray;
rectangle (0, 0, trunc (k_x * sum), 50);
pen.Color: = clRed;
brush.Style: = bsClear;
textOut (0,51, '0 ');
curr_x: = 0;
curr_x_scr: = 0;
for i: = 0 to detailAmount-1 do
begin
for j: = 0 to x [i] -1 do
begin
curr_x: = curr_x + details [i]. l;
curr_x_scr: = curr_x_scr + k_x * details [i]. l;
if curr_x <> materialLength then
begin
moveTo (trunc (curr_x_scr), 0);
lineTo (trunc (curr_x_scr), 50);
textOut (trunc (curr_x_scr), 51, intToStr (curr_x));
/ / TextOut (trunc (curr_x_scr-15), 21, '(' + intToStr (i +1 )+')');
end;
end;
end;
end;
end;
/ / Вихід з програми
procedure TForm_Main.Button_ExitClick (Sender: TObject);
begin
close;
end;
/ / Зміна кількості детеалей
procedure TForm_Main.Edit_DetailAmountChange (Sender: TObject);
var
new_d_a: integer;
i: integer;
begin
new_d_a: = strToInt (Form_Main.Edit_DetailAmount.Text);
if (new_d_a> = 1) then
begin
if (new_d_a <= MAX_DETAIL_AMOUNT) then
begin
Form_Main.StringGrid_In.RowCount: = new_d_a +1;
for i: = 1 to new_d_a do
begin
Form_Main.StringGrid_In.Cells [0, i]: = intToStr (i);
end;
end
else
begin
Form_Main.Edit_DetailAmount.Text: = intToStr (MAX_DETAIL_AMOUNT);
end;
end
else
begin
Form_Main.Edit_DetailAmount.Text: = intToStr (1);
end;
end;
/ / Ініціалізація програми
procedure TForm_Main.FormCreate (Sender: TObject);
begin
Form_Main.UpDown_MaterialLength.Min: = 1;
Form_Main.UpDown_MaterialLength.Max: = MAX_MATERIAL_LENGTH;
Form_Main.UpDown_DetailAmount.Min: = 1;
Form_Main.UpDown_DetailAmount.Max: = MAX_DETAIL_AMOUNT;
Form_Main.StringGrid_In.Cells [0,0]: = '№ деталі';
Form_Main.StringGrid_In.Cells [1,0]: = 'Довжина';
Form_Main.StringGrid_In.Cells [2,0]: = 'Ціна';
Form_Main.StringGrid_In.Cells [0,1]: = '1 ';
Form_Main.StringGrid_Out1.Cells [0,0]: = '№ деталі';
Form_Main.StringGrid_Out1.Cells [1,0]: = 'Кількість';
end;
/ / Зміна довжини матеріалу
procedure TForm_Main.Edit_MaterialLengthChange (Sender: TObject);
var
new_m_l: integer;
begin
new_m_l: = strToInt (Form_Main.Edit_MaterialLength.Text);
if (new_m_l> = 1) then
begin
if not (new_m_l <= MAX_MATERIAL_LENGTH) then
begin
Form_Main.Edit_MaterialLength.Text: = intToStr (MAX_MATERIAL_LENGTH);
end;
end
else
begin
Form_Main.Edit_MaterialLength.Text: = intToStr (1);
end;
end;
/ / Сортування даних за зростанням довжини деталі
procedure StrGridSort;
var
i: integer;
do_next: boolean;
begin
do_next: = true;
while do_next do
begin
do_next: = false;
for i: = 1 to Form_Main.StringGrid_In.RowCount-2 do
begin
if strToInt (Form_Main.StringGrid_In.Cells [1, i])>
strToInt (Form_Main.StringGrid_In.Cells [1, i +1]) then
begin
Form_Main.StringGrid_In.cols [1]. Exchange (i, i +1);
Form_Main.StringGrid_In.cols [2]. Exchange (i, i +1);
do_next: = true;
end;
end;
end;
end;
/ / Обчислення раціонального розкрою і відображення результату
procedure TForm_Main.Button_CalculateClick (Sender: TObject);
var
i, sum, cost: integer;
begin
strGridSort;
updateData;
searchRationalCut (materialLength, detailAmount, details, x);
Form_Main.StringGrid_Out1.RowCount: = detailAmount +1;
sum: = 0; cost: = 0;
for i: = 1 to detailAmount do
begin
Form_Main.StringGrid_Out1.Cells [0, i]: = intToStr (i);
Form_Main.StringGrid_Out1.Cells [1, i]: = intToStr (x [i]);
sum: = sum + x [i] * details [i]. l;
cost: = cost + x [i] * details [i]. c;
end;
Form_Main.Edit1.Text: = intToStr (cost);
Form_Main.Edit2.Text: = intToStr (materialLength-sum);
drawRationalCut (Form_Main.Image_Cut, materialLength, detailAmount, details, x);
end;
procedure TForm_Main.Button1Click (Sender: TObject);
begin
Form2.Show;
end;
end.
Література
1. Е.А. Мухачева "Раціональний розкрій промислових матеріалів". Москва, Машинобудування, 1984 р.
2. Е.А. Мухачева, Г.Ш. Рубінштейн "Математичне програмування". Новосибірськ, Наука, 1977 р.