
- •Введение. Экономико-математические методы и модели Основные понятия экономико-математического моделирования
- •Этапы экономико-математического моделирования
- •Классификация экономико-математических моделей
- •1. Обзор методов сетевого планирования и управления
- •1.1. Развитие методов сетевого планирования и управления
- •1.1.1. Назначение систем сетевого планирования и управления
- •1.1.2. Возникновение методов сетевого планирования и управления
- •1.1.3. Практическое применение методов сетевого планирования и управления. Программные средства, основанные на методах сетевого планирования и управления
- •1.2. Классификация систем сетевого планирования и управления
- •1.3. Элементы и параметры сетевого графика
- •1.3.1. Построение сетевой модели проекта
- •1.3.2. Правила построения сетевых графиков
- •1.3.3. Временные параметры сетевых графиков
- •1.4. Оптимизация сетевых графиков
- •1.4.1. Типы оптимизационных задач
- •1.4.2. Оптимизация сетевого графика по стоимости. Постановка задачи оптимизации. Методы оптимизации.
- •1.5. Алгоритмы, использованные для решения задачи оптимизации проекта по стоимости
- •1.5.1. Общие принципы решения задачи
- •Задача о максимальном потоке
- •1.5.2. Алгоритм поиска ранних сроков свершения событий
- •1.5.3. Алгоритм Келли (оптимизация по критерию "время-стоимость")
- •Алгоритм решения параметрической задачи
- •Определяется новый оптимальный план по формулам
- •1.5.4. Алгоритм поиска минимальной стоимости при заданной продолжительности критического пути Тд
- •2. Описание программыnet_planning
- •2.1. Краткое описание возможностей программы
- •2.2. Постановка задачи контрольного примера
- •2.3. Решение контрольного примера на основе алгоритма Келли
- •2.4. Решение задачи с использованием программыnet_planning
- •Заключение
- •Литературные источники
- •Приложение а. Связи между различными вариантами классификации систем сетевого планирования и управления
- •Приложение б. Текст программы
- •Приложение в. Текстовый файл отчета
- •Приложение г. Структурные схемы алгоритмов и основных процедур.
Приложение а. Связи между различными вариантами классификации систем сетевого планирования и управления
Рис А1 Классификация систем сетевого планирования и управления
Приложение б. Текст программы
unit net_planning_file;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids, ComCtrls, Tabnotbk, StdCtrls;
type
TForm1 = class(TForm)
TabbedNotebook1: TTabbedNotebook;
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
Label2: TLabel;
Edit2: TEdit;
StringGrid1: TStringGrid;
Button2: TButton;
StringGrid2: TStringGrid;
Button3: TButton;
ComboBox1: TComboBox;
Memo1: TMemo;
ComboBox2: TComboBox;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Edit3: TEdit;
Label8: TLabel;
Edit4: TEdit;
Label9: TLabel;
Edit5: TEdit;
Edit6: TEdit;
Label10: TLabel;
Label11: TLabel;
Button4: TButton;
StringGrid3: TStringGrid;
Button5: TButton;
StringGrid4: TStringGrid;
Edit7: TEdit;
Label12: TLabel;
StringGrid5: TStringGrid;
Label13: TLabel;
Label14: TLabel;
Button6: TButton;
Label15: TLabel;
Label16: TLabel;
Label17: TLabel;
Label18: TLabel;
Label19: TLabel;
Label21: TLabel;
Label22: TLabel;
Label23: TLabel;
Label20: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure StringGrid3SelectCell(Sender: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
procedure Button6Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const infinity=1000000000000000000000000000000.0; //бесконечность
type
TEvent=record // событие
name:string; // имя
number:integer; // номер
early_date:extended; // ранний срок свершения
vu_label:boolean; // принадлежит {u} или {v}
end;
TWork=record // работа
name:string; // имя
number:integer; // номер
initial_event:integer; // начальное событие
final_event:integer; // конечное событие
initial_event_name:string; // имя начального события
final_event_name:string; // имя конечного события
cost_a:extended; // a[i,j]
cost_b:extended; // b[i,j]
cost:extended; // c[i,j]
d_big:extended; // D[i,j]
d_little:extended; // d[i,j]
t:extended; // продолжительность t[i,j]
existance:boolean; // существует работа между i и j
work_is_cut:boolean; // попадает ли работа в сечение
end;
TPrevious=record
epsilon:array[0..100,0..100] of integer;
atta:array[0..100] of integer;
teta0:extended;
end;
works_t=array[0..100,0..100] of TWork;
event_t=array[0..100] of TEvent;
work_t=array[1..100] of TWork;
tableT=array[0..100,0..100] of extended; // значение элемента таблицы
table_fullT=array[0..100,0..100] of boolean; // заполнен ли элемент таблицы
T_teta_array=array[0..100,0..100] of extended;
var
Form1: TForm1;
report:TextFile;
works,answer_works,previous_work:Works_t;
event,answer_event,previous_event:event_t;
work,answer_work:Work_t;
previous:TPrevious;
n_event:integer; //количество событий
n_work:integer; //количество работ
work_count:integer;
table:tableT;
table_full:table_fullT;
the_end:boolean; // равен "истина", если
//получен граф с минимально возможным Ткр
cost:extended; //общая стоимость проекта
critical_path:extended; // Тд
critical_path_min:extended; // минимально возможный Ткр
work_to_change:integer;
implementation
{$R *.DFM}
function check_integer(s:string):boolean;
// проверяет, возможно ли перевести строку s в
// целое число из отрезка [2;100]
var tf:boolean ;
i:integer;
const numbers:set of char=['0','1','2','3','4','5','6','7','8','9'];
begin
tf:=true;
if length(s)<>0 then
begin
for i:=1 to length(s) do
if not(s[i] in numbers) then tf:=false;
end
else tf:=false;
if (tf=true) and ((StrToInt(s)<2)or(StrToInt(s)>100))then tf:=false;
check_integer:=tf;
end;
function check_extended(s:string):boolean;
// проверяет, возможно ли перевести строку s в
// действительное неотрицательное число
var tf:boolean ;
i:integer;
count_comma:integer;
const numbers:set of char=['0','1','2','3','4','5','6','7','8','9','.'];
begin
count_comma:=0;
tf:=true;
if length(s)<>0 then
for i:=1 to length(s) do
begin
if not(s[i] in numbers) then
tf:=false;
if s[i]='.' then
count_comma:=count_comma+1;
end
else tf:=false;
if s[1]='.' then tf:=false;
if count_comma>1 then tf:=false;
check_extended:=tf;
end;
function check_names(n_row:integer;grid_label:integer):boolean;
// проверяет, что в списках событий и работ
// нет объектов с одинаковыми именами
var i,j:integer;
tf:boolean;
begin
tf:=true;
for i:=1 to n_row do
for j:=1 to n_row do
begin
if grid_label=1 then
if (form1.StringGrid1.Cells[1,i]=form1.StringGrid1.Cells[1,j])
and (i<>j)then
tf:=false;
if grid_label=2 then
if (form1.StringGrid2.Cells[1,i]=form1.StringGrid2.Cells[1,j])
and (i<>j)then
tf:=false;
end;
check_names:=tf;
end;
function check_matrix_existence(var error_cycle,
error_connected:boolean):boolean;
//проверяет, что граф является сетью и что в сети нет циклов
Type error_vector=array[0..100] of boolean;
var error_connected_i,error_connected_j:error_vector;
i,j:integer;
global_error:boolean;
begin
error_cycle:=false;
error_connected:=false;
for i:=0 to n_event do
begin
error_connected_i[i]:=true;
error_connected_j[i]:=true;
end;
error_connected_i[n_event]:=false;
error_connected_j[0]:=false;
for i:=0 to n_event do
for j:=0 to n_event do
begin
if (works[i,j].existance=true)and (j<=i) then
error_cycle:=true;
if (works[i,j].existance=true)and (i<>n_event) then
error_connected_i[i]:=false;
if (works[i,j].existance=true)and (j<>0) then
error_connected_j[j]:=false;
end;
for i:=0 to n_event do
if (error_connected_i[i]=true) or (error_connected_j[i]=true)then
error_connected:=true;
if (error_cycle=true) or (error_connected=true) then
global_error:=true
else global_error:=false;
check_matrix_existence:=global_error;
end;
function check_combobox(combobox_number:integer):boolean;
// проверяет, что событие, выбранное в качестве начального или
// конечного для работы, существует
var i:integer;
string_existence:boolean;
begin
string_existence:=false;
for i:=0 to n_event do
begin
if combobox_number=1 then
if form1.ComboBox1.Text=event[i].name then string_existence:=true;
if combobox_number=2 then
if form1.ComboBox2.Text=event[i].name then string_existence:=true;
end;
check_combobox:=string_existence;
end;
procedure make_string_longer(long:integer;var short_string:string);
//добавление пробелов к строке short_string до длины long
begin
if length(short_string)<long then
repeat
short_string:=short_string+' ';
until length(short_string)>=long
end;
procedure page_0_visible(tf:boolean);
//видимость/невидимость страницы "размер"
begin
Form1.edit1.Visible:=tf;
Form1.edit2.Visible:=tf;
Form1.label1.Visible:=tf;
Form1.label2.Visible:=tf;
Form1.Button1.Visible:=tf;
end;
procedure page_1_visible(tf:boolean);
//видимость/невидимость страницы "события"
begin
Form1.StringGrid1.Visible:=tf;
Form1.Button2.Visible:=tf;
end;
procedure page_2_visible(tf:boolean);
//видимость/невидимость страницы "работы"
begin
Form1.StringGrid2.Visible:=tf;
Form1.Button3.Visible:=tf;
end;
procedure page_3_visible(tf:boolean);
//видимость/невидимость страницы "данные о работах"
begin
form1.label3.Visible:=tf;
form1.label4.Visible:=tf;
form1.label5.Visible:=tf;
form1.label6.Visible:=tf;
form1.label7.Visible:=tf;
form1.label8.Visible:=tf;
form1.label9.Visible:=tf;
form1.label10.Visible:=tf;
form1.label11.Visible:=tf;
form1.edit3.Visible:=tf;
form1.edit4.Visible:=tf;
form1.edit5.Visible:=tf;
form1.edit6.Visible:=tf;
form1.combobox1.Visible:=tf;
form1.combobox2.Visible:=tf;
form1.memo1.Visible:=tf;
end;
procedure page_4_visible(tf:boolean);
//видимость/невидимость страницы "просмотр данных"
begin
form1.label12.Visible:=tf;
form1.edit7.Visible:=tf;
Form1.StringGrid3.Visible:=tf;
Form1.Button5.Visible:=tf;
Form1.Label17.Visible:=tf;
Form1.Label18.Visible:=tf;
Form1.Label19.Visible:=tf;
Form1.Label21.Visible:=tf;
Form1.Label22.Visible:=tf;
Form1.Label23.Visible:=tf;
end;
procedure page_5_visible(tf:boolean);
//видимость/невидимость страницы "результат"
begin
Form1.StringGrid4.Visible:=tf;
Form1.StringGrid5.Visible:=tf;
Form1.Label13.Visible:=tf;
Form1.Label14.Visible:=tf;
Form1.Label15.Visible:=tf;
Form1.Label16.Visible:=tf;
end;
procedure page_3_clearing;
//начальные значения на страницу "данные о работах"
begin
form1.Memo1.clear;
form1.edit3.Text:='1';
form1.edit4.Text:='20';
form1.edit5.Text:='1';
form1.edit6.Text:='2';
form1.combobox1.text:='';
form1.combobox2.text:='';
end;
procedure work_add(n:integer);
//добавление данных о работе со страницы "данные о работах"
var i,k,m:integer;
begin
work[n].existance:=true;
work[n].initial_event_name:=form1.ComboBox1.text;
work[n].final_event_name:=form1.ComboBox2.Text;
for i:=0 to n_event do
begin
if work[n].initial_event_name=event[i].name then
begin
work[n].initial_event:=event[i].number;
k:=work[n].initial_event;
end;
end;
for i:=0 to n_event do
begin
if work[n].final_event_name=event[i].name then
begin
work[n].final_event:=event[i].number;
m:=work[n].final_event
end;
end;
works[k,m].name:=work[n].name;
works[k,m].existance:=true;
works[k,m].initial_event:=k;
works[k,m].final_event:=m;
works[k,m].initial_event_name:=work[n].initial_event_name;
works[k,m].final_event_name:=work[n].final_event_name;
works[k,m].cost_a:=StrToFloat(form1.edit3.text);
works[k,m].cost_b:=StrToFloat(form1.edit4.text);
works[k,m].d_big:=StrToFloat(form1.edit6.text);
works[k,m].d_little:=StrToFloat(form1.edit5.text);
work[n].cost_a:=StrToFloat(form1.edit3.text);
work[n].cost_b:=StrToFloat(form1.edit4.text);
work[n].d_big:=StrToFloat(form1.edit6.text);
work[n].d_little:=StrToFloat(form1.edit5.text);
end;
procedure from_works_to_work;
//переход от матрицы работ оптимального плана к списку работ
var i,j,k:integer;
begin
for k:=1 to n_work do
for i:=0 to n_event do
for j:=0 to n_event do
begin
if work[k].name=answer_works[i,j].name then
begin
work[k].t:=answer_works[i,j].t;
work[k].cost:=answer_works[i,j].cost;
end;
end;
end;
procedure page_4_view;
//вывод исходных данных
var i:integer;
begin
page_4_visible(true);
form1.StringGrid3.RowCount:=n_work+1;
form1.StringGrid3.cells[0,0]:='номер';
form1.StringGrid3.cells[1,0]:='название';
form1.StringGrid3.cells[2,0]:='(i,j)';
form1.StringGrid3.cells[3,0]:='a[i,j]';
form1.StringGrid3.cells[4,0]:='b[i,j]';
form1.StringGrid3.cells[5,0]:='d[i,j]';
form1.StringGrid3.cells[6,0]:='D[i,j]';
for i:=1 to n_work do
begin
form1.StringGrid3.cells[0,i]:=IntToStr(work[i].number);
form1.StringGrid3.cells[1,i]:=work[i].name;
form1.StringGrid3.cells[2,i]:='('+intToStr(work[i].initial_event)+','
+intToStr(work[i].final_event)+')';
form1.StringGrid3.cells[3,i]:=FloatToStrF(work[i].cost_a,fffixed,5,2);
form1.StringGrid3.cells[4,i]:=FloatToStrF(work[i].cost_b,fffixed,5,2);
form1.StringGrid3.cells[5,i]:=FloatToStrF(work[i].d_little,fffixed,5,2);
form1.StringGrid3.cells[6,i]:=FloatToStrF(work[i].d_big,fffixed,5,2);
end;
end;
procedure output_results;
//вывод результатов
var i:integer;
s,s_name,s_numbers,s_time,s_cost:string;
begin
form1.StringGrid4.RowCount:=n_work+1;
form1.StringGrid4.cells[0,0]:='номер';
form1.StringGrid4.cells[1,0]:='название';
form1.StringGrid4.cells[2,0]:='(i,j)';
form1.StringGrid4.cells[3,0]:='t[i,j]';
form1.StringGrid4.cells[4,0]:='c[i,j]';
for i:=1 to n_work do
begin
form1.StringGrid4.cells[0,i]:=IntToStr(work[i].number);
form1.StringGrid4.cells[1,i]:=work[i].name;
form1.StringGrid4.cells[2,i]:='('+intToStr(work[i].initial_event)+','
+intToStr(work[i].final_event)+')';
form1.StringGrid4.cells[3,i]:=FloatToStrF(work[i].t,fffixed,7,4);
form1.StringGrid4.cells[4,i]:=FloatToStrF(work[i].cost,fffixed,10,4);
end;
form1.StringGrid5.RowCount:=n_event+2;
form1.StringGrid5.cells[0,0]:='номер';
form1.StringGrid5.cells[1,0]:='название';
form1.StringGrid5.cells[2,0]:='T[j]';
for i:=1 to n_event+1 do
begin
form1.StringGrid5.cells[0,i]:=IntToStr(answer_event[i-1].number);
form1.StringGrid5.cells[1,i]:=answer_event[i-1].name;
form1.StringGrid5.cells[2,i]:=
FloatToStrF(answer_event[i-1].early_date,fffixed,7,4);
end;
form1.label14.Caption:=FloatToStrF(cost,fffixed,10,4);
writeln(report,'****************************'); //вывод в файл
writeln(report,'****************************');
writeln(report,'ОТВЕТ');
writeln(report,'работы');
writeln(report,'| имя ||время ||стоимость|');
for i:=1 to n_work do
begin
s:='';
s_name:='|'+work[i].name;
make_string_longer(15,s_name);
s:=s+s_name;
s_numbers:='('+IntToStr(work[i].initial_event)+','+
IntToStr(work[i].final_event)+')';
make_string_longer(9,s_numbers);
s:=s+s_numbers+'||';
s_time:=FloatToStrF(work[i].t,fffixed,5,2);
make_string_longer(10,s_time);
s:=s+s_time+'||';
s_cost:=FloatToStrF(work[i].cost,fffixed,5,2);
make_string_longer(9,s_cost);
s:=s+s_cost+'|';
writeln(report,s);
end;
writeln(report,'ранние сроки свершения событий:');
for i:=0 to n_event do
begin
s:=IntToStr(i)+'-->'+
FloatToStrF(answer_event[i].early_date,fffixed,5,2);
writeln(report,s);
end;
writeln(report,'стоимость=',FloatToStrF(cost,fffixed,5,2));
end;
procedure add_to_file_tabble;
//вывод в файл таблицы поиска максимального потока
var i,j:integer;
s:array[0..100,0..100] of string;
long_s,s0,s1:string;
begin
s0:=' ';
for i:=0 to n_event do
begin
s1:=IntToStr(i);
make_string_longer(10,s1);
s0:=s0+s1;
end;
writeln(report,s0);
for i:=0 to n_event do
for j:=0 to n_event do
begin
if table_full[i,j]=true then
begin
if table[i,j]<infinity/100 then
begin
s[i,j]:='|'+FloatToStrF(table[i,j],fffixed,7,2);
make_string_longer(9,s[i,j]);
s[i,j]:=s[i,j]+'|';
end
else s[i,j]:='|'+'infinity'+'|';
end
else s[i,j]:='|'+'________'+'|';
end;
for i:=0 to n_event do
begin
long_s:=intToStr(i)+' ';
for j:=0 to n_event do
long_s:=long_s+s[i,j];
writeln(report,long_s);
end;
end;
procedure add_to_file_works;
//вывод в файл текущего оптимального плана
var i,j:integer;
s,s1:string;
s_work:array[0..100,0..100] of string;
begin
for i:=0 to n_event do
for j:=0 to n_event do
begin
s_work[i,j]:='|'+FloatToStrF(works[i,j].t,fffixed,7,2);
make_string_longer(9,s_work[i,j]);
s_work[i,j]:=s_work[i,j]+'|';
end;
writeln(report,'длительность работ:');
s:=' ';
for i:=0 to n_event do
begin
s1:=IntToStr(i);
make_string_longer(10,s1);
s:=s+s1;
end;
writeln(report,s);
for i:=0 to n_event do
begin
s:=IntToStr(i);
make_string_longer(3,s);
for j:=0 to n_event do
s:=s+s_work[i,j];
writeln(report,s);
end;
writeln(report,'ранние сроки свершения событий:');
for i:=0 to n_event do
begin
s:=intToStr(i)+'-->'+FloatToStrF(event[i].early_date,fffixed,8,2);
writeln(report,s);
end;
end;
procedure table_padding;
//распределение работ по множествам E1,E2,Q1,Q2,Q3,Q4
var i,j:integer;
s:array[0..100,0..100] of string;
EQ:string;
begin
for i:=0 to n_event do
for j:=i to n_event do
if works[i,j].existance=true then
begin
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t=works[i,j].d_big)
and (works[i,j].t>works[i,j].d_little) then
//E1&Q1
begin
if works[i,j].work_is_cut=false then
begin
table[i,j]:=works[i,j].cost_a;
table[j,i]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q1|';
s[j,i]:='|_____|';
end;
if works[i,j].work_is_cut=true then
begin
if (event[i].vu_label=false)and(event[j].vu_label=true) then
begin
table[i,j]:=works[i,j].cost_a;
table[j,i]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q1|';
s[j,i]:='|_____|';
end;
if (event[i].vu_label=true)and(event[j].vu_label=false) then
begin
table[j,i]:=works[i,j].cost_a;
table[i,j]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q1|';
s[j,i]:='|_____|';
end;
end;
end;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t=works[i,j].d_big)
and (works[i,j].t=works[i,j].d_little) then
begin
//E1&Q2
table[i,j]:=infinity;
table[j,i]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q2|';
s[j,i]:='|_____|';
end;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t<works[i,j].d_big)
and (works[i,j].t=works[i,j].d_little) then
begin
//E1&Q3
table[i,j]:=infinity;
table[j,i]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q3|';
s[j,i]:='|_____|';
end;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t<works[i,j].d_big)
and (works[i,j].t>works[i,j].d_little) then
begin
//E1&Q4
table[i,j]:=0;
table[j,i]:=0;
table_full[i,j]:=true;
table_full[j,i]:=true;
s[i,j]:='|E1&Q4|';
s[j,i]:='|_____|';
end;
if (event[j].early_date-event[i].early_date-works[i,j].t>0)
and (works[i,j].t=works[i,j].d_big)
and (works[i,j].t>=works[i,j].d_little) then
begin
//E2
table_full[i,j]:=false;
table_full[j,i]:=false;
s[i,j]:='|__E2_|';
s[j,i]:='|_____|';
end;
end
else
begin
table_full[i,j]:=false;
s[i,j]:='|_____|';
s[j,i]:='|_____|';
end;
writeln(report,'*********************************');
// вывод в файл
for i:=0 to n_event do
write(report,i:7);
writeln(report,'');
for i:=0 to n_event do
begin
EQ:=IntToStr(i);
make_string_longer(3,EQ);
for j:=0 to n_event do
EQ:=EQ+s[i,j];
writeln(report,EQ);
end;
end;
procedure cross_table;
//поиск максимального потока
var i,j:integer;
way_label:array[0..100,0..100] of boolean;
way_label_new:array[0..100,0..100] of boolean;
col_label:array[0..100] of integer;
col_is_pointed:array[0..100] of boolean;
row_is_pointed:array[0..100] of boolean;
plus:array[0..100,0..100] of boolean;
no_way:boolean;
cell_is_pointed:array[0..100,0..100] of boolean;
min:extended;
summa_cost_a:extended;
i_min:integer;
s,s1,col_label_string:string;
plus_minus:array[0..100,0..100]of string;
n:integer;
begin
for i:=0 to n_event do
for j:=0 to n_event do
if works[i,j].existance=true then
works[i,j].work_is_cut:=false;
event[0].vu_label:=false;
no_way:=false;
min:=0;
while (no_way=false)and(min<infinity) do
begin
for i:=0 to n_event do
begin
col_is_pointed[i]:=false;
row_is_pointed[i]:=false;
event[i].vu_label:=true; {in v}
end;
event[0].vu_label:=false;
for i:=0 to n_event do
for j:=0 to n_event do
begin
way_label[i,j]:=false;
cell_is_pointed[i,j]:=false;
way_label_new[i,j]:=false;
end;
row_is_pointed[0]:=true;
for i:=0 to n_event do //поиск путей из 0 в n
for j:=0 to n_event do
if table_full[i,j]=true then
begin
if (table[i,j]>0) and
(col_is_pointed[j]=false)and
(row_is_pointed[i]=true) then
begin
col_label[j]:=i;
col_is_pointed[j]:=true;
row_is_pointed[j]:=true;
way_label[i,j]:=true;
event[j].vu_label:=false; {in u}
end;
end;
if col_is_pointed[n_event]=true then
no_way:=false;
if col_is_pointed[n_event]=false then
no_way:=true;
if (no_way=false) then
begin
for i:=0 to n_event do
if way_label[i,n_event]=true then
begin
cell_is_pointed[i,n_event]:=true;
i_min:=i;
end;
for i:=0 to n_event do
for j:=0 to n_event do
plus_minus[i,j]:='| |';
for j:=n_event downto 1 do //возвращение из n в 0
for i:=n_event downto 0 do
if (way_label[i,j]=true) and (cell_is_pointed[i,j]=true) then
begin
plus[col_label[j],j]:=false;
plus_minus[col_label[j],j]:='| - |';
plus[j,col_label[j]]:=true;
plus_minus[j,col_label[j]]:='| + |';
way_label_new[col_label[j],j]:=true;
way_label_new[j,col_label[j]]:=true;
cell_is_pointed[col_label[col_label[j]],col_label[j]]:=true;
end ;
writeln(report,''); //вывод в файл
add_to_file_tabble;
s:=' ';
for i:=0 to n_event do
begin
s1:=IntToStr(i);
make_string_longer(5,s1);
s:=s+s1;
end;
writeln(report,s);
for i:=0 to n_event do
begin
s:=IntToStr(i);
make_string_longer(3,s);
for j:=0 to n_event do
s:=s+plus_minus[i,j];
writeln(report,s);
end;
min:=table[i_min,n_event]; //поиск пропускной
//способности и пересчет таблицы
for i:=n_event downto 0 do
for j:=n_event downto 0 do
if (plus[i,j]=false) and(table_full[i,j]=true)and
(way_label_new[i,j]=true) then
if table[i,j]<min then
min:=table[i,j];
writeln(report,'h=',FloatToStrF(min,fffixed,7,2));
if min<(infinity) then
begin
for i:=n_event downto 0 do
for j:=n_event downto 0 do
if way_label_new[i,j]=true then
begin
if plus[i,j]=true then
table[i,j]:=table[i,j]+min;
if plus[i,j]=false then
table[i,j]:=table[i,j]-min;
end;
end
else the_end:=true;
end
else add_to_file_tabble;
end;
for i:=0 to n_event do //отмечаются работы, попавшие в сечение
for j:=0 to n_event do
if (works[i,j].existance=true)
and((event[i].vu_label=false)and(event[j].vu_label=true)
or (event[j].vu_label=false)and(event[i].vu_label=true)) then
works[i,j].work_is_cut:=true;
end;
procedure teta_array_clear(var teta_array:T_teta_array);
var i,j:integer;
begin
for i:=0 to n_event do
for j:=0 to n_event do
teta_array[i,j]:=0;
end;
procedure teta_count(teta_array:T_teta_array;
var teta_x:extended);
var i,j:integer;
begin
for i:=0 to n_event do
for j:=0 to n_event do
if (works[i,j].existance=true)and (teta_array[i,j]>0)
and(teta_array[i,j]<teta_x)then
teta_x:=teta_array[i,j];
end;
procedure count_cost;
//расчет стоимости плана
var i,j:integer;
begin
cost:=0;
for i:=0 to n_event do
for j:=0 to n_event do
if works[i,j].existance=true then
begin
works[i,j].cost:=-works[i,j].t*works[i,j].cost_a+works[i,j].cost_b;
cost:=cost+works[i,j].cost;
end;
end;
procedure recount_limit;
//решение двойственной задачи
var i,j:integer;
s,s1:string;
epsilon:array[0..100,0..100] of integer;
atta:array[0..100] of integer;
teta:array[1..3]of extended;
sigma:array[0..100,0..100] of extended;
teta_array:T_teta_array;
teta0:extended;
begin
if the_end=false then
begin
//нахождение переменных двойственной задачи
for i:=0 to n_event do
if event[i].vu_label=true then atta[i]:=1
else atta[i]:=0;
writeln(report,'распределение по множествам {u} и {v}:');
for i:=0 to n_event do
begin
if atta[i]=0 then
s:=IntToStr(i)+'-->'+'u';
if atta[i]=1 then
s:=IntToStr(i)+'-->'+'v';
writeln(report,s);
end;
for i:=0 to n_event do
for j:=0 to n_event do
epsilon[i,j]:=0;
for i:=0 to n_event do
for j:=0 to n_event do
if works[i,j].work_is_cut=true then
begin
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t>works[i,j].d_little)
and (works[i,j].t=works[i,j].d_big)
and (atta[i]=0)and(atta[j]=1)then
//E1&Q1
epsilon[i,j]:=1;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t>works[i,j].d_little)
and (works[i,j].t<works[i,j].d_big)
and (atta[i]=0)and(atta[j]=1)then
//E1&Q4
epsilon[i,j]:=1;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t=works[i,j].d_little)
and (works[i,j].t<works[i,j].d_big)
and (atta[i]=1)and(atta[j]=0)then
//E1&Q3
epsilon[i,j]:=-1;
if (event[j].early_date-event[i].early_date-works[i,j].t=0)
and (works[i,j].t>works[i,j].d_little)
and (works[i,j].t<works[i,j].d_big)
and (atta[i]=1)and(atta[j]=0)then
//E1&Q4
epsilon[i,j]:=-1;
end;
writeln(report,'epsilon=');
s:=' ';
for i:=0 to n_event do
begin
s1:=IntToStr(i);
make_string_longer(4,s1);
s:=s+s1;
end;
writeln(report,s);
for i:=0 to n_event do
begin
s:=IntToStr(i);
make_string_longer(3,s);
for j:=0 to n_event do
begin
if epsilon[i,j]=-1 then s:=s+'|-1|';
if epsilon[i,j]=1 then s:=s+'|+1|';
if epsilon[i,j]=0 then s:=s+'|__|';
end;
writeln(report,s);
end;
for i:=1 to 3 do
teta[i]:=0;
for i:=0 to n_event do
for j:=0 to n_event do
if works[i,j].existance=true then
sigma[i,j]:=epsilon[i,j]+atta[i]-atta[j];
teta_array_clear(teta_array);
for i:=0 to n_event do
for j:=0 to n_event do
if (works[i,j].existance=true)and(sigma[i,j]<0) then
begin
teta_array[i,j]:=
(event[j].early_date-event[i].early_date-works[i,j].t)/(-sigma[i,j]);
teta[1]:=teta_array[i,j];
end;
teta_count(teta_array,teta[1]);
teta_array_clear(teta_array);
for i:=0 to n_event do
for j:=0 to n_event do
if (works[i,j].existance=true)and (epsilon[i,j]<>0)then
begin
teta_array[i,j]:=(works[i,j].t-works[i,j].d_big)/epsilon[i,j];
teta[2]:=teta_array[i,j];
end;
teta_count(teta_array,teta[2]);
teta_array_clear(teta_array);
for i:=0 to n_event do
for j:=0 to n_event do
if (works[i,j].existance=true)and (epsilon[i,j]<>0)then
begin
teta_array[i,j]:=(works[i,j].t-works[i,j].d_little)/epsilon[i,j];
teta[3]:=teta_array[i,j];
end;
teta_count(teta_array,teta[3]);
writeln(report,'teta1=',FloatToStrF(teta[1],fffixed,6,2));
writeln(report,'teta2=',FloatToStrF(teta[2],fffixed,6,2));
writeln(report,'teta3=',FloatToStrF(teta[3],fffixed,6,2));
for i:=1 to 3 do
if (teta[i]>0)then teta0:=teta[i];
for i:=1 to 3 do
if (teta[i]>0) and (teta[i]<teta0)then teta0:=teta[i];
if teta0<=0 then the_end:=true
else the_end:=false;
writeln(report,'teta0=',FloatToStrF(teta0,fffixed,6,2));
for i:=0 to n_event do //расчет нового оптимального плана,
for j:=0 to n_event do //сравнение нового Ткр с предыдущим и с Тд
begin
previous_work[i,j]:=works[i,j];
previous.epsilon[i,j]:=epsilon[i,j];
works[i,j].t:=works[i,j].t-teta0*epsilon[i,j];
end;
for i:=0 to n_event do
begin
previous_event[i]:=event[i];
previous.atta[i]:=atta[i];
event[i].early_date:=event[i].early_date-teta0*atta[i];
end;
add_to_file_works;
count_cost;
if (critical_path<=previous_event[n_event].early_date)and
(critical_path>event[n_event].early_date)then
begin
add_to_file_works;
previous.teta0:=0;
if previous.atta[n_event]=1 then
previous.teta0:=previous_event[n_event].early_date-critical_path;
writeln(report,'teta=',FloatToStrF(previous.teta0,fffixed,6,2));
for i:=0 to n_event do
answer_event[i]:=previous_event[i];
for i:=0 to n_event do
answer_event[i].early_date:=previous_event[i].early_date-
(previous.teta0*previous.atta[i]);
for i:=0 to n_event do
for j:=0 to n_event do
answer_works[i,j]:=previous_work[i,j];
for i:=0 to n_event do
for j:=0 to n_event do
answer_works[i,j].t:=previous_work[i,j].t-
(previous.teta0*previous.epsilon[i,j]);
cost:=0;
for i:=0 to n_event do
for j:=0 to n_event do
if answer_works[i,j].existance=true then
begin
answer_works[i,j].cost:=-answer_works[i,j].t*answer_works[i,j].cost_a+
answer_works[i,j].cost_b;
cost:=cost+answer_works[i,j].cost;
end;
the_end:=true;
end;
end;
if (the_end=true) and
(critical_path=critical_path_min)then
begin
for i:=0 to n_event do
for j:=0 to n_event do
answer_works[i,j]:=works[i,j];
for i:=0 to n_event do
answer_event[i]:=event[i];
writeln(report,'teta: нет');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TabbedNotebook1.PageIndex:=0;
page_0_visible(true);
edit1.text:='5';
edit2.text:='5';
page_1_visible(false);
page_2_visible(false);
button4.Visible:=false;
page_3_visible(false);
page_4_visible(false);
page_5_visible(false);
form1.Button6.Visible:=false;
end;
procedure TForm1.Button1Click(Sender: TObject);
//ввод количества событий и работ
var i:integer;
begin
if (check_integer(edit1.Text)=true) and (check_integer(edit2.Text)=true) then
begin
n_work:=StrToInt(edit2.Text);
n_event:=StrToInt(edit1.Text);
page_1_visible(true);
StringGrid2.RowCount:=n_work+1;
for i:=1 to n_Work do
begin
StringGrid2.cells[0,i]:=IntToStr(i);
StringGrid2.cells[1,i]:='работа'+IntToStr(i);
end;
StringGrid2.cells[1,0]:='название';
StringGrid2.cells[0,0]:='номер';
StringGrid1.RowCount:=n_event+2;
for i:=1 to n_event+1 do
begin
StringGrid1.cells[0,i]:=IntToStr(i-1);
StringGrid1.cells[1,i]:='событие'+IntToStr(i-1);
end;
StringGrid1.cells[1,0]:='название';
StringGrid1.cells[0,0]:='номер';
end
else showMessage('неверно введена размерность');
end;
procedure TForm1.Button2Click(Sender: TObject);
//ввод названий событий
var i,j:integer;
begin
combobox1.Clear;
combobox2.Clear;
if check_names(n_event+1,1)=true then
begin
for i:=0 to n_event do
begin
event[i].name:=StringGrid1.cells[1,i+1];
event[i].number:=StrToInt(StringGrid1.cells[0,i+1]);
comboBox1.items.Insert(i,event[i].name);
comboBox2.items.Insert(i,event[i].name);
end;
for i:=0 to n_event do
for j:=0 to n_event do
works[i,j].existance:=false;
page_0_visible(false);
page_2_visible(true);
// TabbedNotebook1.PageIndex:=2;
end
else showMessage('имена не должны повторяться!');
end;
procedure TForm1.Button3Click(Sender: TObject);
//ввод названий работ
var i:integer;
begin
if check_names(n_work,2)=true then
begin
for i:=1 to n_Work do
begin
work[i].name:=StringGrid2.cells[1,i];
work[i].number:=StrToInt(StringGrid2.cells[0,i]);
end;
button4.Visible:=true;
work_count:=1;
page_3_clearing;
memo1.lines.add(work[work_count].name);
page_1_visible(false);
page_3_visible(true);
TabbedNotebook1.PageIndex:=3;
page_2_visible(false);
end
else showMessage('имена не должны повторяться!');
end;
function twins(work_number:integer):boolean;
//поиск событий i и j, связанных более чем одной работой
var i:integer;
tf:boolean;
name1,name2:string;
string_number_i,string_number_j:integer;
begin
tf:=true;
string_number_i:=Form1.ComboBox1.ItemIndex;
string_number_j:=Form1.ComboBox2.ItemIndex;
name1:=form1.ComboBox1.items[string_number_i];
name2:=form1.ComboBox2.items[string_number_j];
if work_number>1 then
begin
for i:=1 to work_number do
if (name1=work[i].initial_event_name)and
(name2=work[i].final_event_name)then
tf:=false;
end;
twins:=tf;
end;
procedure TForm1.Button4Click(Sender: TObject);
// кнопка "добавить"
begin
if(work_count<=n_work)and(work_count>0)
and (check_extended(edit3.Text)=true) and (check_extended(edit4.Text)=true)
and (check_extended(edit5.Text)=true)
and (check_extended(edit6.Text)=true)
and (twins(work_count)=true) then
begin
if (check_combobox(1)=true) and(check_combobox(2)=true) then
begin
if strToFloat(edit5.text)<=strToFloat(edit6.text)then
begin
work_add(work_count);
page_3_clearing;
work_count:=1+work_count;
memo1.lines.add(work[work_count].name);
end
else showMessage('D[i,j] не может быть меньше d[i,j]');
end
else showMessage('такого события нет');
end
else
begin
if twins(work_count)=false then
showMessage('между этими событиями уже есть работа')
else
showMessage('ошибка при вводе числа');
end;
if work_count>n_work then
begin
button4.Visible:=false;
page_2_visible(false);
page_3_visible(false);
page_4_view;
end;
end;
procedure count_max_min(max_min:integer;var border:extended);
//расчет Tj
var i,j:integer;
lambda:array[0..100] of extended;
begin
for i:=0 to n_event do
for j:=0 to n_event do
begin
if (works[i,j].existance=true) and (max_min=1) then
works[i,j].t:=works[i,j].d_big;
if (works[i,j].existance=true) and (max_min=0) then
works[i,j].t:=works[i,j].d_little;
end;
event[0].early_date:=0;
for j:=1 to n_event do
begin
event[j].early_date:=0;
for i:=0 to j do
begin
if (works[i,j].existance=true)and (max_min=1)then
lambda[i]:=event[i].early_date+works[i,j].d_big;
if (works[i,j].existance=true)and (max_min=0)then
lambda[i]:=event[i].early_date+works[i,j].d_little;
end;
for i:=0 to j do
begin
if (works[i,j].existance=true) and
(lambda[i]>event[j].early_date) then
event[j].early_date:=lambda[i];
end;
end;
count_cost;
border:=event[n_event].early_date;
if max_min=1 then
begin
form1.Label21.Caption:=FloatToStrF(border,fffixed,12,2);
form1.Label22.Caption:=FloatToStrF(cost,fffixed,12,2);
end;
if max_min=0 then
begin
form1.Label23.Caption:=FloatToStrF(border,fffixed,12,2);
end;
end;
procedure TForm1.Button5Click(Sender: TObject);
//кнопка "расчет"
var i,j:integer;
error_cycle, error_connected:boolean;
s_name,s_events,s_a,s_b,s_d_big,s_d_little,message_string:string;
border_min,border_max:extended;
begin
if (check_extended(edit7.Text)=true) and
(check_matrix_existence(error_cycle,error_connected)=false) then
begin
critical_path:=StrToFloat(edit7.Text);
the_end:=false;
count_max_min(0,border_min);
count_max_min(1,border_max);
critical_path_min:=border_min;
if (critical_path>=border_min) and (critical_path<=border_max) then
begin
AssignFile(report,'net_report.txt');
Rewrite(report);
Writeln(report,'исходные данные:');
Writeln(report,'количество событий: ',n_event:4);
Writeln(report,'количество работ: ',n_work:6);
Writeln(report,'критический путь: ',critical_path:10:3);
Writeln(report,'');
Writeln(report,'данные о событиях:');
for i:=0 to n_event do
Writeln(report,IntToStr(event[i].number)+'_'+event[i].name);
Writeln(report,'');
Writeln(report,'данные о работах:');
Writeln(report,' имя: d[i,j]'+
' D[i,j] a[i,j] b[i,j] ');
for i:=1 to n_work do
begin
s_name:=work[i].name;
make_string_longer(15,s_name);
s_events:='('+IntToStr(work[i].initial_event)+','+
IntToStr(work[i].final_event)+')';
make_string_longer(9,s_events);
s_d_little:=FloatToStrF(work[i].d_little,fffixed,7,3);
make_string_longer(12,s_d_little);
s_d_big:=FloatToStrF(work[i].d_big,fffixed,7,3);
make_string_longer(12,s_d_big);
s_a:=FloatToStrF(work[i].cost_a,fffixed,7,3);
make_string_longer(12,s_a);
s_b:=FloatToStrF(work[i].cost_b,fffixed,7,3);
make_string_longer(12,s_b);
Writeln(report,'|'+s_events+'|'+s_name+'|'+
s_d_little+'|'+s_d_big+'|'+s_a+'|'+s_b);
end;
add_to_file_works;
while the_end=false do
begin
table_padding;
cross_table;
recount_limit;
end;
from_works_to_work;
page_5_visible(true);
output_results;
TabbedNotebook1.PageIndex:=5;
CloseFile(report);
end
else showMessage('для такого Ткр задача не может быть решена')
end
else
begin
if check_extended(edit7.Text)=false then
message_string:='ошибка при вводе числа';
if error_cycle=true then
message_string:='в сети есть циклы';
if error_connected=true then
message_string:='граф не является сетью';
showMessage(message_string);
end;
end;
procedure TForm1.StringGrid3SelectCell(Sender: TObject; ACol,
ARow: Integer; var CanSelect: Boolean);
//выбор работы, данные о которой необходимо изменить
begin
if (ARow<>0) and (ACol=1) then
begin
work_to_change:=ARow;
form1.Button6.Visible:=true;
page_3_visible(true);
form1.ComboBox1.Text:=work[work_to_change].initial_event_name;
form1.ComboBox2.Text:=work[work_to_change].final_event_name;
form1.Edit3.Text:=FloatToStr(work[work_to_change].cost_a);
form1.Edit4.Text:=FloatToStr(work[work_to_change].cost_b);
form1.Edit6.Text:=FloatToStr(work[work_to_change].d_big);
form1.Edit5.Text:=FloatToStr(work[work_to_change].d_little);
TabbedNotebook1.PageIndex:=3;
memo1.lines.add(work[ARow].name);
work[work_to_change].existance:=false;
works[work[work_to_change].initial_event,
work[work_to_change].final_event].existance:=false;
end;
end;
procedure TForm1.Button6Click(Sender: TObject);
//кнопка "изменить"
begin
if (check_combobox(1)=true) and(check_combobox(2)=true) then
begin
work_add(work_to_change);
page_4_view;
TabbedNotebook1.PageIndex:=4;
Page_3_visible(false);
button6.Visible:=false;
end
else showMessage('такого события нет');
end;
end.