program Simplex;

uses crt;

const
  AllocX=30;           {reserverer hukommelse til x s=F8jer (antal variab=
le)}
  AllocY=10;           {reserverer hukommelse til y r=E6kker (antal ligni=
nger)}
  KropX=22;            {antal s=F8jler i kroppen, som bruges i Simplex-be=
regningen}
  KropY=3;             {antal r=E6kker i kroppen, ------------- do ------=
---------}
  M=32000;             {fungerer som "uendeligt"/meget stort tal}
  vname:array[0..allocx] of string=
  ('--',' a',' b',' c',' d',' e',' f',' g',' h',' i',' j',' k',' l',' m',' =
n',' o',' p','s1','s2','s3','a1'
  ,'a2','a3','--','--','--','--','--','--','--','--');

Type
  RaekkeType=array[1..allocx] of real;
  SoejleType=array[1..allocy] of real;
  Kroptype=array[1..allocx,1..allocy] of real;

var
  basis:array[1..allocy] of integer;{basis variablene}
  quantity:soejletype;              {kvantitet}
  c:kroptype;                       {Krop+enhedsprofit+enhedspris+CZ-r=E6kk=
en}
  Incoming,Outgoing:integer;        {Inkomne- og udg=E5ende-variabel}
  pivot:real;                       {Pivot element}
  cj,zj,cz:raekketype;              {Unitprofit,unitlosses,CZ}

procedure InitVar;
const
  Preunitprofit:raekketype=(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,=
-1,0,0,0,-m,-m,-m,0,0,0,0,0,0,0,0);
var
  i,j:integer;
procedure skm(row,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x1=
7,x18,x19,x20,
              x21,x22,x23,x24,x25,x26,x27,x28,x29,x30:integer);
begin
  c[1,row]:=x1; c[2,row]:=x2; c[3,row]:=x3; c[4,row]:=x4; c[5,row]:=
=x5;
  c[6,row]:=x6; c[7,row]:=x7; c[8,row]:=x8; c[9,row]:=x9; c[10,row]=
:=x10;
  c[11,row]:=x11; c[12,row]:=x12; c[13,row]:=x13; c[14,row]:=x14; c=
[15,row]:=x15;
  c[16,row]:=x16; c[17,row]:=x17; c[18,row]:=x18; c[19,row]:=x19; c=
[20,row]:=x20;
  c[21,row]:=x21; c[22,row]:=x22; c[23,row]:=x23; c[24,row]:=x24; c=
[25,row]:=x25;
  c[26,row]:=x26; c[27,row]:=x27; c[28,row]:=x28; c[29,row]:=x29; c=
[30,row]:=x30;
end;
begin
  skm(1, 2,1,1,1,1,0,0,0,0,0,0,0,3,2,2,1,-1,0,0,1,0,0,0,0,0,0,0,0,0,0);
  skm(2, 10,8,12,16,20,30,6,10,14,18,22,26,0,2,6,4,0,-1,0,0,1,0,0,0,0,0,0,0=
,0,0);
  skm(3, 0,3,2,1,0,0,6,5,4,3,2,1,0,2,1,4,0,0,-1,0,0,1,0,0,0,0,0,0,0,0);
  skm(4, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  skm(5, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  for i:=1 to allocy do basis[i]:=0;
  basis[1]:=20; basis[2]:=21; basis[3]:=22;
  {Cj} j:=4; for i:=1 to kropx do cj[i]:=preunitprofit[i];
  {ZJ} j:=5; for i:=1 to kropx do zj[i]:=0;
  {CZ} j:=6; for i:=1 to kropx do cz[i]:=0;
  Incoming:=0; Outgoing:=0;
  for i:=1 to allocy do quantity[i]:=0;
  quantity[1]:=1500; quantity[2]:=750; quantity[3]:=400;
  pivot:=0;
end;

procedure ShowTab;
var
  i,j:integer;
  maxt:integer; {maksimale tekst som kan st=E5 p=E5 en linie}
begin
  writeln('+----------------------------------Tableau----------------------=
--------------+');
  write('| Basis  Quantity   ');
  maxt:=kropx; if maxt>8 then maxt:=8;
  for i:=1 to maxt do write(vname[i],'     '); gotoxy(79,wherey); writeln=
('|');
  writeln('+---------------------------------------------------------------=
--------------+');
  for j:=1 to kropy do begin
    write('|  ',vname[basis[j]],'    ',quantity[j]:6:1,'  ');
    maxt:=kropx; if maxt>8 then maxt:=8;
    for i:=1 to maxt do write('  ',c[i,j]:3:1,'  '); gotoxy(79,wherey); w=
riteln('|');
  end;
  writeln('+---------------------------------------------------------------=
--------------+');
  write('|  Unit Profit   ');
  maxt:=kropx; if maxt>8 then maxt:=8; for i:=1 to maxt do write(cj[i=
]:5:1,'  '); gotoxy(79,wherey); writeln('|');
  write('|  Unit Losses   ');
  maxt:=kropx; if maxt>8 then maxt:=8; for i:=1 to maxt do write(zj[i=
]:5:1,'  '); gotoxy(79,wherey); writeln('|');
  write('|  Cj-Zj         ');
  maxt:=kropx; if maxt>8 then maxt:=8; for i:=1 to maxt do write(cz[i=
]:5:1,'  '); gotoxy(79,wherey); writeln('|');
  writeln('+---------------------------------------------------------------=
--------------+');
end;

function TestOptimal:boolean;
var
  i:integer;
  optimal:boolean;
begin
  optimal:=true;
  for i:=1 to kropx do if cz[i]>0 then optimal:=false;
  TestOptimal:=optimal;
end;

function FindIncomingVar:integer;
var
  i,num:integer;
  min:real;
begin
  min:=0; num:=0;
  {finder kun en mulig, der kan faktisk eksistere flere}
  for i:=1 to kropx do begin
    if (cz[i]>min) and (cz[i]>0) then begin min:=cz[i]; num:=i; end;
  end;
  FindIncomingVar:=num;
end;

function FindOutgoingVar:integer;
var
  ratio:array[1..kropy] of real;
  j,num:integer;
  min:real;
begin
  for j:=1 to kropy do begin
    if c[incoming,j]=0 then ratio[j]:=m else
    ratio[j]:=quantity[j]/c[incoming,j];
  end;
  min:=M; num:=0;
  for j:=1 to kropy do begin
    if (ratio[j]<min) and (ratio[j]>=0) then begin min:=ratio[j]; num:=
=j; end;
  end;
  FindOutgoingVar:=num;
end;

function FindPivot:real;
begin
  findpivot:=c[incoming,outgoing];
end;

procedure CalcZRow;
var
  i,j:integer;
  sum:real;
begin
  for i:=1 to kropx do begin
    sum:=0;
    for j:=1 to kropy do sum:=sum+cj[basis[j]]*c[i,j];
    zj[i]:=sum;
  end;
end;

procedure CalcCZRow;
var i:integer;
begin
  for i:=1 to kropx do cz[i]:=cj[i]-zj[i];
end;

function RundNed(x:real):real;
{Finder det mindste hele tal af en reel v=E6rdi. Bruges da man ikke kan lav=
e
 fx. 3,5 enheder, man kan kun 3}
begin
  RundNed:=trunc(x);
end;

procedure ChangeBasis;
begin
  basis[outgoing]:=incoming;
end;

procedure TransformOutgoingRow;
var
  i:integer;
begin
  for i:=1 to kropx do c[i,outgoing]:=c[i,outgoing]/pivot;
  quantity[outgoing]:=quantity[outgoing]/pivot; {kvantitet rundes ikke ne=
d, dvs. der bruges reelle tal}
  ChangeBasis;                                  {brug funktionen RundNed, h=
vis der skal bruges hele tal}
end;

procedure TransOtherRows;
{other= andre end outgoing row}
var
  i,j:integer;
  k:real;                           {koefficint som bruges til at danne tra=
nsformations-r=E6kke}
  trans:array[1..kropx] of real; {transformationsr=E6kke}
  transq:real;                   {transformations-konstant, til kvantitet}
begin
  for j:=1 to kropy do begin
    if j<>outgoing then begin {transformerer kun andre end udeg=E5ende r=E6=
kker}
      k:=c[incoming,j];       {k findes i sk=E6ringen mellem den aktuelle=
 r=E6kke og den indkomne s=F8jle}
      transq:=quantity[outgoing]*k;             {transformationskonstant =
som bruges til trans. af kvantiten}
      for i:=1 to kropx do trans[i]:=c[i,outgoing]*k; {transformationsr=
=E6kken dannes}
      for i:=1 to kropx do c[i,j]:=c[i,j]-trans[i];   {aktuelle r=E6kke=
 transformeres med trans. r=E6kken}
      quantity[j]:=quantity[j]-transq;                   {kvantiteten i a=
ktuelle r=E6kke transformeres med transq}
    end;
  end;
end;


procedure ImproveSolution;
begin
  Incoming:=FindIncomingVar;
  Outgoing:=FindOutgoingVar;
  Pivot:=FindPivot;
  TransformOutgoingRow;
  TransOtherRows;
  CalcZRow;
  CalcCZRow;
end;

procedure MakeInitSolution;
{ Finder den initialiserende l=F8sning}
begin
  CalcZRow;
  CalcCZRow;
end;

procedure ShowVar;
var
  i:integer;
begin
  writeln('+----------------------------------Solution---------------------=
--------------+');
  for i:=1 to 3 do begin
    write('|  ',vname[basis[i]],'= ',quantity[i]:6:3);
    gotoxy(79,wherey); writeln('|');
  end;
  writeln('+---------------------------------------------------------------=
--------------+');
end;

procedure Solve;
var
  optimal:boolean;
begin
  MakeInitSolution;
  ShowTab;
  Optimal:=TestOptimal;
  While not Optimal do begin
    ImproveSolution;
    {showtab; repeat until keypressed; readkey;}
    Optimal:=TestOptimal;
  end;
  {find evt. andre optimale l=F8sninger}
  {ShowTab;}
  ShowVar;
end;

begin
  clrscr;
  InitVar;
  Solve;
  repeat until keypressed;
end.

