Смекни!
smekni.com

Багатокритеріальна задача лінійного програмування (стр. 8 из 17)

координат рядка-заголовка та стовпця заголовка (верхнього лівого кута

таблиці з заголовками): HeadColNumInGrid і HeadRowNumInGrid.}

Var CurFloatVal:TWorkFloat; CurElmType:THeadLineElmType;

Begin

CurElmType:=CurHeadCol[SRow].ElmType;

CurFloatVal:=0;

Try {Пробуємо розпізнати число:}

CurFloatVal:=StrToFloat (CurGrid. Cells [Self.CHeadColNum,

SRow+bc_LTaskRowsBeforeVars+Self.CHeadRowNum]);

CurElmType:=bc_Number; {якщо число розпізналося, то це число}

Except{Якщо рядок не інтерпретується як число, але комірка вважалася

такою, що містить число або змінну, то вважаємо його назвою функції

(бо це не число, і не повинно бути змінною – усі змінні спочатку

у рядку-заголовку):}

If (CurElmType<>bc_FuncVal) and (CurElmType<>bc_DestFuncToMax) and

(CurElmType<>bc_DestFuncToMin) then

CurElmType:=bc_FuncVal;

End; {Виправлений тип елемента:}

CurHeadCol[SRow].ElmType:=CurElmType;

If CurElmType=bc_Number then {записуємо число, якщо розпізналося:}

CurHeadCol[SRow].AsNumber:=CurFloatVal

Else

Begin {якщо число не розпізналося, то записуємо як назву змінної:}

With CurHeadCol[SRow] do

Begin

AsVarName:=CurGrid. Cells [Self.CHeadColNum,

SRow+bc_LTaskRowsBeforeVars+Self.CHeadRowNum]; {назва}

VarInitPos:=SRow; {номер п/п у стовпці в умові задачі}

{Ознака, що змінна спочатку була у стовпці-заголовку:}

VarInitInRow:=False;

End;

End;

End;

Function TGridFormattingProcs. ReadTableFromGrid: Boolean;

Const sc_CurProcName='ReadTableFromGrid';

{Процедура для зчитування таблиці та її заголовків із CurGrid.

Для екранної таблиці використовуються координати рядка-заголовка та

стовпця заголовка (верхнього лівого кута таблиці з заголовками):

HeadColNumInGrid (CHeadColNum) і HeadRowNumInGrid (CHeadRowNum).}

Var CurRow, CurCol, CurWidth, CurHeight: Integer;

CurFloatVal:TWorkFloat;

Begin

If Self. CurGrid=Nil then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+

': '+sc_NoGrowingStringGrid);

ReadTableFromGrid:=False;

Exit;

End;

{Ширина і висота таблиці з заголовками:}

CurWidth:=Self. CurGrid. ColCount-Self.CHeadColNum-bc_LTaskColsBeforeVars;

CurHeight:=Self. CurGrid. RowCount-Self.CHeadRowNum-bc_LTaskRowsBeforeVars;

If (CurHeight<=0) or (CurWidth<=0) then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+

': починаючи з комірки ['+IntToStr (Self.CHeadColNum+1)+'; '+

IntToStr (Self.CHeadRowNum+1)+'] таблиці не знайдено' + sc_TriSpot);

ReadTableFromGrid:=False;

Exit;

End;

{Виділяємо пам'ять:}

SetLength (Self. CurHeadRow, CurWidth); {рядок-заголовок}

SetLength (Self. CurHeadCol, CurHeight); {стовпець-заголовок}

SetLength (Self. CurTable, CurHeight, CurWidth); {таблиця}

{Читаємо рядок-заголовок:}

For CurCol:=0 to CurWidth-1 do ReadHeadRowCell(CurCol);

{Читаємо стовпець-заголовок:}

For CurRow:=0 to CurHeight-1 do ReadHeadColCell(CurRow);

{Читаємо таблицю коефіцієнтів:}

For CurRow:=Self.CHeadRowNum+bc_LTaskRowsBeforeVars to

Self. CurGrid. RowCount-1 do

Begin

For CurCol:=Self.CHeadColNum+bc_LTaskColsBeforeVars to

Self. CurGrid. ColCount-1 do

Begin

Try {Пробуємо інтерпретувати рядок із комірки як число:}

CurFloatVal:=StrToFloat (CurGrid. Cells [CurCol, CurRow]);

Except{Якщо не вдалося, то вважаємо це число нулем:}

CurFloatVal:=0;

End;

Self. CurTable [CurRow-bc_LTaskRowsBeforeVars-Self.CHeadRowNum,

CurCol-bc_LTaskColsBeforeVars-Self.CHeadColNum]:=CurFloatVal;

End;

End;

{Після читання зміни в екранній таблиці враховані:}

Self. CurGridModified:=False;

ReadTableFromGrid:=True;

End;

Function TGridFormattingProcs. WriteTableToGrid (SHeadColNum,

SHeadRowNum: Integer; ToTuneColWidth: Boolean=True):Boolean;

{Процедура для відображення таблиці та її заголовків у CurGrid.}

Const sc_CurProcName='WriteTableToGrid';

Var CurRow, CurCol, CurWidth, CurHeight: Integer;

CurElmType:THeadLineElmType;

Begin

If Self. CurGrid=Nil then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+

': GrowingStringGrid не заданий!..');

WriteTableToGrid:=True;

Exit;

End;

{Ширина і висота таблиці:}

Self. GetTaskSizes (CurWidth, CurHeight);

If (CurHeight<=0) or (CurWidth<=0) then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+sc_EmptyTable);

WriteTableToGrid:=False;

Exit;

End;

{Виділяємо комірки для таблиці у екранному CurGrid:}

Self. CurGrid. ColCount:=CurWidth+SHeadColNum+1;

Self. CurGrid. RowCount:=CurHeight+SHeadRowNum+1;

{Відображаємо рядок-заголовок:}

For CurCol:=SHeadColNum+1 to Self. CurGrid. ColCount-1 do

Begin

CurElmType:=CurHeadRow [CurCol-1-SHeadColNum].ElmType;

If CurElmType=bc_Number then {записуємо число, якщо є числом:}

CurGrid. Cells [CurCol, SHeadRowNum]:=

FloatToStr (CurHeadRow[CurCol-1-SHeadColNum].AsNumber)

Else{Якщо це не число, то це рядок з якоюсь назвою. Записуємо:}

Self. CurGrid. Cells [CurCol, SHeadRowNum]:=

CurHeadRow [CurCol-1-SHeadColNum].AsVarName;

End;

{Відображаємо стовпець-заголовок:}

For CurRow:=SHeadRowNum+1 to Self. CurGrid. RowCount-1 do

Begin

CurElmType:=CurHeadCol [CurRow-1-SHeadRowNum].ElmType;

If CurElmType=bc_Number then {записуємо число, якщо є числом:}

CurGrid. Cells [SHeadColNum, CurRow]:=

FloatToStr (CurHeadCol[CurRow-1-SHeadRowNum].AsNumber)

Else{Якщо це не число, то це рядок з якоюсь назвою. Записуємо:}

Self. CurGrid. Cells [SHeadColNum, CurRow]:=

CurHeadCol [CurRow-1-SHeadRowNum].AsVarName;

End;

{Відображаємо таблицю коефіцієнтів:}

For CurRow:=SHeadRowNum+1 to Self. CurGrid. RowCount-1 do

Begin

For CurCol:=SHeadColNum+1 to Self. CurGrid. ColCount-1 do

CurGrid. Cells [CurCol, CurRow]:=

FloatToStr (Self. CurTable [CurRow-1-SHeadRowNum, CurCol-1-SHeadColNum]);

End;

{Комірка на перехресті заголовків пуста:}

If (SHeadRowNum<Self. CurGrid. RowCount) and

(SHeadColNum<Self. CurGrid. ColCount) then

CurGrid. Cells [SHeadColNum, SHeadRowNum]:='';

{Після запису в екранну таблицю: зміни, що могли бути у ній, вважаємо

затертими:}

Self. CurGridModified:=False;

{Якщо задано, настроюємо ширини стовпців по довжині тексту у комірках:}

If ToTuneColWidth then Self. CurGrid. TuneColWidth;

WriteTableToGrid:=True;

End;

Procedure TGridFormattingProcs. GetTaskSizes (Var DWidth, DHeight: Integer);

{Визначення розмірів таблиці задачі, і корегування довжини заголовків

таблиці та зовнішнього масиву таблиці (масиву масивів).}

Begin

DHeight:=Length (Self. CurTable);

If DHeight>0 then

DWidth:=Length (Self. CurTable[0])

Else DWidth:=0;

If DWidth=0 then DHeight:=0;

If DWidth>Length (Self. CurHeadRow) then

DWidth:=Length (Self. CurHeadRow);

If DHeight>Length (Self. CurHeadCol) then

DHeight:=Length (Self. CurHeadCol);

{Якщо комірок немає, то:}

If DWidth=0 then

Begin

{Зовнійшій масив встановлюємо у нульову довжину:}

SetLength (Self. CurTable, 0);

{Заголовки теж:}

SetLength (Self. CurHeadRow, 0);

SetLength (Self. CurHeadCol, 0);

End;

End;

{Розміри прочитаної таблиці задачі:}

Function TGridFormattingProcs. TaskWidth: Integer;

Var CurWidth, CurHeight: Integer;

Begin

Self. GetTaskSizes (CurWidth, CurHeight);

TaskWidth:=CurWidth;

End;

Function TGridFormattingProcs. TaskHeight: Integer;

Var CurWidth, CurHeight: Integer;

Begin

Self. GetTaskSizes (CurWidth, CurHeight);

TaskHeight:=CurHeight;

End;

Function TGridFormattingProcs. GetTask (ToPrepareGrid: Boolean=True):Boolean;

{Зчитування умови задачі із CurGrid та відображення прочитаного

на тому ж місці, де воно було. Працює у режимах

fs_EnteringEqs і fs_EnteringLTask.}

Const sc_CurProcName='GetTask';

Var Res1: Boolean;

Procedure DoGetTask;

Begin

If ToPrepareGrid then

CurGrid. ShrinkToFilled (Self.CHeadColNum+1, Self.CHeadRowNum+1);

{Читаємо комірки таблиці:}

Res1:=Self. ReadTableFromGrid;

{Відображаємо те, що вийшло прочитати, у тих самих комірках на екрані:}

If Not (Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum)) then

Res1:=False;

End;

Begin

If Self. CurGrid=Nil then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+': '+sc_NoGrowingStringGrid);

GetTask:=False;

Exit;

End;

Case Self. CurFormatState of

fs_EnteringEqs: {режим редагування системи лінійних рівнянь:}

Begin

{Зчитуємо таблицю. Як рядок-заголовок зчитуємо автоматично

сформовані назви змінних x1…xn та множник вільних членів (1).

Як стовпець-заголовок зчитуємо стовпець нумерації.

При переході до режиму вирішування задачі у цей стовпець

будуть скопійовані вільні члени (режим способу 1, fs_SolvingEqsM1),

або нулі (режим способу 2, fs_SolvingEqsM2):}

DoGetTask;

If Not(Res1) then Begin GetTask:=False; Exit; End;

End;

fs_EnteringLTask: {режим редагування форми задачі лінійного програмування:}

Begin

{Зчитуємо таблицю умови для задачі ЛП максимізації або

мінімізації лінійної форми (функції з умовами-нерівностями,

рівняннями та обмеженнями невід'ємності, імена змінних, нерівностей,

функцій):}

DoGetTask;

If Not(Res1) then Begin GetTask:=False; Exit; End;

End;

fs_FreeEdit: {режим вільного редагування:}

Begin

{Читаємо таблицю, рядок-заголовок, стовпець-заголовок:}

DoGetTask;

If Not(Res1) then Begin GetTask:=False; Exit; End;

End;

Else {інші режими:}

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName + sc_CantReadTaskInCurMode

+ sc_TriSpot);

GetTask:=False;

Exit;

End;

End;

{If ToPrepareGrid then CurGrid. TuneColWidth;}

Self. EqM1TaskPrepared:=False;

Self. EqM2TaskPrepared:=False;

Self.LTaskPrepared:=False;

GetTask:=True;

End;

Procedure TGridFormattingProcs. Refresh;

Const sc_CurProcName='Refresh';

Var Res1: Boolean;

Begin

If Self. CurFormatState<>fs_NoFormatting then

Begin

If Self. CurGrid=Nil then

Begin

If Self. CurOutConsole<>Nil then

Self. CurOutConsole. Lines. Add (sc_CurProcName+': '+

sc_NoGrowingStringGrid);

Exit;

End;

Res1:=False;

{Якщо таблиця редагована або ще не читана, то запускаємо її зчитування:}

If Self. CurGridModified or (Self. TaskWidth<=0) then Res1:=Self. GetTask;

If Not(Res1) then {Якщо таблиця не була віджображена у GetTask, відображаємо:}

Self. WriteTableToGrid (Self.CHeadColNum, Self.CHeadRowNum);

End;

End;

Procedure TGridFormattingProcs. ResetModified; {скидає прапорець зміненого стану}

Begin

Self. CurGridModified:=False;

End;

Procedure TGridFormattingProcs. UndoChanges;

{Відкидає останні зміни (ResetModified+Refresh).}

Begin

Self. ResetModified; Self. Refresh;

End;

Procedure Transpose (Var SDMatrix:TFloatMatrix);

{Транспонування двовимірної матриці.}

Var CurCol, CurRow, CurWidth, CurHeight: Integer;

SafeElm:TWorkFloat;

Begin

CurHeight:=Length(SDMatrix);

If CurHeight>0 then CurWidth:=Length (SDMatrix[0])

Else CurWidth:=0;

If (CurHeight=0) or (CurWidth=0) then Exit;

{Збільшуємо розміри матриці до квадратних:}

IfCurWidth>CurHeightthen{Якщо ширина була більша за висоту:}

Begin

SetLength (SDMatrix, CurWidth, CurWidth); {збільшуємо висоту}

End

ElseifCurWidth<CurHeightthen{Якщо висота була більша за ширину:}

Begin

SetLength (SDMatrix, CurHeight, CurHeight); {збільшуємо ширину}

End;

{Міняємо елементи місцями: рядки будуть стовпцями, а стовпці – рядками:}

For CurRow:=0 to Length(SDMatrix) – 1 do

Begin

For CurCol:=CurRow + 1 to Length (SDMatrix[CurRow]) – 1 do

Begin

SafeElm:=SDMatrix [CurRow, CurCol];

SDMatrix [CurRow, CurCol]:=SDMatrix [CurCol, CurRow];

SDMatrix [CurCol, CurRow]:=SafeElm;

End;

End;

{Ширина тепер буде така як була висота, а висота – як була ширина:}

SetLength (SDMatrix, CurWidth, CurHeight);

End;

Function TGridFormattingProcs. MakeDualLTask: Boolean;

{Перехід від зчитаної умови задачі максимізації чи мінімізації

лінійної форми до двоїстої задачі. Працює у режимі редагування

задачі максимізації-мінімізації (fs_EnteringLTask).

За правилом двоїсту задачу потрібно мінімізувати, якщо для прямої

потрібно було знайти максимум, і максимізувати, якщо для прямої потрібно

було знайти мінімум.