home *** CD-ROM | disk | FTP | other *** search
/ Chip 1999 March / Chip_1999-03_cd.bin / zkuste / delphi / INFO / DI9806RS.ZIP / DecideF.pas < prev   
Pascal/Delphi Source File  |  1998-02-05  |  13KB  |  451 lines

  1. unit DecideF;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, ExtCtrls, Menus;
  8.  
  9. type
  10.   TDecideForm = class(TForm)
  11.     Label1: TLabel;
  12.     CmdRandomize: TButton;
  13.     NumChoicesText: TEdit;
  14.     CostLabel1: TLabel;
  15.     ProfitLabel1: TLabel;
  16.     CostLabel2: TLabel;
  17.     ProfitLabel11: TLabel;
  18.     CostLabel21: TLabel;
  19.     ProfitLabel21: TLabel;
  20.     Label2: TLabel;
  21.     Label3: TLabel;
  22.     TotalCostLabel: TStaticText;
  23.     TotalProfitLabel: TStaticText;
  24.     CmdSearch: TButton;
  25.     Label4: TLabel;
  26.     Label5: TLabel;
  27.     AlgorithmOption: TRadioGroup;
  28.     Label6: TLabel;
  29.     MinCostText: TEdit;
  30.     MaxCostText: TEdit;
  31.     Label7: TLabel;
  32.     Label8: TLabel;
  33.     MinProfitText: TEdit;
  34.     MaxProfitText: TEdit;
  35.     Label9: TLabel;
  36.     Label10: TLabel;
  37.     NodesVisitedLabel: TStaticText;
  38.     Label11: TLabel;
  39.     MaxAvailableText: TEdit;
  40.     MainMenu1: TMainMenu;
  41.     File1: TMenuItem;
  42.     mnuExit: TMenuItem;
  43.     procedure FormCreate(Sender: TObject);
  44.     procedure CmdRandomizeClick(Sender: TObject);
  45.     procedure CmdSearchClick(Sender: TObject);
  46.  
  47.     procedure BranchAndBound(test_item : Integer);
  48.     procedure SearchExhaustively(test_item : Integer);
  49.     procedure HillClimbing;
  50.     procedure SearchRandomly;
  51.     procedure ShowResults;
  52.     procedure ResetSolution;
  53.     procedure DisableSearch(Sender: TObject);
  54.     procedure mnuExitClick(Sender: TObject);
  55.   private
  56.     { Private declarations }
  57.   public
  58.     { Public declarations }
  59.   end;
  60.  
  61. var
  62.   DecideForm: TDecideForm;
  63.  
  64. implementation
  65.  
  66. {$R *.DFM}
  67.  
  68. const
  69.     MAX_CHOICES = 40;
  70. var
  71.     CostLabel   : array [1..MAX_CHOICES] of TStaticText;
  72.     ProfitLabel : array [1..MAX_CHOICES] of TStaticText;
  73.  
  74.     NumChoices, CostAvailable : Integer;
  75.     TestProfit, TestCost, BestProfit, UnusedProfit : Integer;
  76.     Cost, Profit     : array [1..MAX_CHOICES] of Integer;
  77.     TestUse, BestUse : array [1..MAX_CHOICES] of Boolean;
  78.     NodesVisited     : Integer;
  79.  
  80. procedure TDecideForm.FormCreate(Sender: TObject);
  81. const
  82.     GAP = 3;
  83. var
  84.     cost_left, profit_left : Integer;
  85.     top, wid, hgt, diff    : Integer;
  86.     i                      : Integer;
  87. begin
  88.     // Initialize the random number generator.
  89.     Randomize;
  90.  
  91.     // Create cost, profit, and use controls.
  92.     hgt := 17;
  93.     wid := CostLabel1.Width;
  94.     cost_left := CostLabel1.Left;
  95.     profit_left := ProfitLabel1.Left;
  96.     top := CostLabel1.Top + CostLabel1.Height + GAP;
  97.     diff := CostLabel2.Left - CostLabel1.Left;
  98.  
  99.     for i := 1 to MAX_CHOICES do
  100.     begin
  101.         CostLabel[i] := TStaticText.Create(Self);
  102.         CostLabel[i].Parent := Self;
  103.         CostLabel[i].SetBounds(cost_left, top, wid, hgt);
  104.         CostLabel[i].AutoSize := False;
  105.         CostLabel[i].BorderStyle := sbsSunken;
  106.  
  107.         ProfitLabel[i] := TStaticText.Create(Self);
  108.         ProfitLabel[i].Parent := Self;
  109.         ProfitLabel[i].SetBounds(profit_left, top, wid, hgt);
  110.         ProfitLabel[i].AutoSize := False;
  111.         ProfitLabel[i].BorderStyle := sbsSunken;
  112.  
  113.         if (i Mod 10 = 0) then
  114.         begin
  115.             cost_left := cost_left + diff;
  116.             profit_left := profit_left + diff;
  117.             top := CostLabel1.Top + CostLabel1.Height + GAP;
  118.         end else
  119.             top := top + hgt + GAP;
  120.     end; // End creating controls.
  121. end;
  122.  
  123. procedure TDecideForm.CmdRandomizeClick(Sender: TObject);
  124. var
  125.     i, min_cost, CostAvailable, min_profit, max_profit : Integer;
  126. begin
  127.     NumChoices := StrToInt(NumChoicesText.Text);
  128.     min_cost := StrToInt(MinCostText.Text);
  129.     CostAvailable := StrToInt(MaxCostText.Text);
  130.     min_profit := StrToInt(MinProfitText.Text);
  131.     max_profit := StrToInt(MaxProfitText.Text);
  132.  
  133.     for i := 1 to NumChoices do
  134.     begin
  135.         Cost[i] := Trunc(Random(CostAvailable - min_cost + 1)) + min_cost;
  136.         CostLabel[i].Caption := Format('%d', [Cost[i]]);
  137.         Profit[i] := Trunc(Random(20)) + 5;
  138.         Profit[i] := Trunc(Random(max_profit - min_profit + 1)) + min_profit;
  139.         ProfitLabel[i].Caption := Format('%d', [Profit[i]]);
  140.     end;
  141.  
  142.     for i := NumChoices + 1 to MAX_CHOICES do
  143.     begin
  144.         CostLabel[i].Caption := '';
  145.         ProfitLabel[i].Caption := '';
  146.     end;
  147.  
  148.     // Reset the best solution colors.
  149.     ResetSolution;
  150.  
  151.     CmdSearch.Enabled := True;
  152. end;
  153.  
  154. procedure TDecideForm.CmdSearchClick(Sender: TObject);
  155. begin
  156.     Screen.Cursor := crHourglass;
  157.  
  158.     // Start with no solution.
  159.     ResetSolution;
  160.  
  161.     // Perform the search.
  162.     case AlgorithmOption.ItemIndex of
  163.         0 : SearchExhaustively(1);
  164.         1 : BranchAndBound(1);
  165.         2 : HillClimbing;
  166.         3 : SearchRandomly;
  167.     end;
  168.  
  169.     // Display the results.
  170.     ShowResults;
  171.  
  172.     Screen.Cursor := crDefault;
  173. end;
  174.  
  175. // Perform a branch and bound search assuming items
  176. // 1 through (test_item - 1) are fixed.
  177. procedure TDecideForm.BranchAndBound(test_item : Integer);
  178. var
  179.     i : Integer;
  180. begin
  181.     NodesVisited := NodesVisited + 1;
  182.  
  183.     // If we've reached a leaf node, we know
  184.     // this solution is an improvement.
  185.     if (test_item > NumChoices) then
  186.     begin
  187.         for i := 1 to NumChoices do
  188.             BestUse[i] := TestUse[i];
  189.         BestProfit := TestProfit;
  190.         Exit;
  191.     end;
  192.  
  193.     // Try to add test_item to the test solution.
  194.     if ((TestCost + Cost[test_item] <= CostAvailable) and
  195.         (TestProfit + UnusedProfit > BestProfit)) then
  196.     begin
  197.         // Add it.
  198.         TestUse[test_item] := True;
  199.         TestCost := TestCost + Cost[test_item];
  200.         TestProfit := TestProfit + Profit[test_item];
  201.         UnusedProfit := UnusedProfit - Profit[test_item];
  202.  
  203.         // Recursively test this solution.
  204.         BranchAndBound(test_item + 1);
  205.  
  206.         // Take the item back out of the solution.
  207.         TestUse[test_item] := False;
  208.         TestCost := TestCost - Cost[test_item];
  209.         TestProfit := TestProfit - Profit[test_item];
  210.         UnusedProfit := UnusedProfit + Profit[test_item];
  211.     end;
  212.  
  213.     // Try a solution without test_item.
  214.     if (TestProfit + UnusedProfit - Profit[test_item]
  215.             > BestProfit) then
  216.     begin
  217.         UnusedProfit := UnusedProfit - Profit[test_item];
  218.         BranchAndBound(test_item + 1);
  219.         UnusedProfit := UnusedProfit + Profit[test_item];
  220.     end;
  221. end;
  222.  
  223. // Perform an exhaustive search assuming items
  224. // 1 through (test_item - 1) are fixed.
  225. procedure TDecideForm.SearchExhaustively(test_item : Integer);
  226. var
  227.     i : Integer;
  228. begin
  229.     NodesVisited := NodesVisited + 1;
  230.  
  231.     // If we have assigned every item, see if we have
  232.     // found an improved solution.
  233.     if (test_item > NumChoices) Then
  234.     begin
  235.         if ((TestCost <= CostAvailable) and
  236.             (TestProfit > BestProfit)) then
  237.         begin
  238.             // Save the improved solution.
  239.             for i := 1 to NumChoices do
  240.                 BestUse[i] := TestUse[i];
  241.             BestProfit := TestProfit;
  242.         end;
  243.         Exit;
  244.     end;
  245.  
  246.     // Add test_item to the test solution.
  247.     TestUse[test_item] := True;
  248.     TestCost := TestCost + Cost[test_item];
  249.     TestProfit := TestProfit + Profit[test_item];
  250.  
  251.     // Recursively see what we can find.
  252.     SearchExhaustively(test_item + 1);
  253.  
  254.     // Take test_item back out of the test solution.
  255.     TestUse[test_item] := False;
  256.     TestCost := TestCost - Cost[test_item];
  257.     TestProfit := TestProfit - Profit[test_item];
  258.  
  259.     // Recursively see what solution we can find
  260.     // without test_item in the solution.
  261.     SearchExhaustively(test_item + 1);
  262. end;
  263.  
  264. // Find a solution using a hill climbing heuristic.
  265. procedure TDecideForm.HillClimbing;
  266. var
  267.     unspent, best_i, best_profit, i : Integer;
  268. begin
  269.     unspent := CostAvailable;
  270.     
  271.     // Repeatedly look for an item to add to the solution.
  272.     while (True) do
  273.     begin
  274.         // Find the item with largest profit that fits
  275.         // in the solution.
  276.         best_profit := -1;
  277.         best_i := -1;
  278.         for i := 1 to NumChoices do
  279.         begin
  280.             // This is not really nodes visited, but it's
  281.             // something we can use for comparison.
  282.             NodesVisited := NodesVisited + 1;
  283.  
  284.             // If the item has not yet been used, and if
  285.             // we have the funds to afford it, and if it
  286.             // gives better profit, take it.
  287.             if ((not BestUse[i]) and
  288.                 (Cost[i] <= unspent) and
  289.                 (Profit[i] > best_profit)) Then
  290.             begin
  291.                 best_i := i;
  292.                 best_profit := Profit[i];
  293.             end;
  294.         end;
  295.  
  296.         // If best_i < 0, no more items will fit
  297.         // in the solution so we're done.
  298.         if (best_i < 0) then Exit;
  299.  
  300.         // Add the item found to the solution.
  301.         BestUse[best_i] := True;
  302.         BestProfit := BestProfit + best_profit;
  303.         unspent := unspent - Cost[best_i];
  304.     end;
  305. end;
  306.  
  307. // Find a solution using a randomized heuristic.
  308. procedure TDecideForm.SearchRandomly;
  309. const
  310.     NUM_TRIALS = 1000;
  311. var
  312.     trial, unspent, num_items, num, i : Integer;
  313. begin
  314.     // Attempt NUM_TRAILS * NumChoices trials.
  315.     for trial := 1 to NUM_TRIALS * NumChoices do
  316.     begin
  317.         unspent := CostAvailable;
  318.  
  319.         // Add randomly selected items to the solution
  320.         // until no more will fit.
  321.         while (True) do
  322.         begin
  323.             // See how many items can fit in the solution.
  324.             num_items := 0;
  325.             for i := 1 to NumChoices do
  326.                 if ((not TestUse[i]) and
  327.                     (Cost[i] <= unspent)) then
  328.                         num_items := num_items + 1;
  329.  
  330.             // This is not really nodes visited, but it's
  331.             // something we can use for comparison. We add
  332.             // NumChoices since we examine all NumChoices
  333.             // nodes.
  334.             NodesVisited := NodesVisited + NumChoices;
  335.  
  336.             // See if no more fit.
  337.             if (num_items < 1) then Break;
  338.  
  339.             // Pick an item randomly.
  340.             num := Trunc(Random(num_items)) + 1;
  341.  
  342.             // Find the item.
  343.             for i := 1 to NumChoices do
  344.                 if ((not TestUse[i]) and
  345.                     (Cost[i] <= unspent)) then
  346.                 begin
  347.                     num := num - 1;
  348.                     if (num < 1) then Break;
  349.                 end;
  350.  
  351.             // Select it.
  352.             TestUse[i] := True;
  353.             unspent := unspent - Cost[i];
  354.             TestProfit := TestProfit + Profit[i];
  355.         end;
  356.  
  357.         // We have finished creating the random solution.
  358.         // See if it an improvement.
  359.         if (TestProfit > BestProfit) then
  360.         begin
  361.             for i := 1 to NumChoices do
  362.             begin
  363.                 for i := 1 to NumChoices do
  364.                     BestUse[i] := TestUse[i];
  365.                 BestProfit := TestProfit;
  366.             end;
  367.         end; // End saving improved solution.
  368.  
  369.         // Reset the test solution for the next trial.
  370.         TestProfit := 0;
  371.         TestCost := 0;
  372.         for i := 1 to NumChoices do
  373.             TestUse[i] := False;
  374.     end; // End of this trial.
  375. end;
  376.  
  377. procedure TDecideForm.ShowResults;
  378. var
  379.     i, best_cost : Integer;
  380. begin
  381.     // Mark the items in the best solution.
  382.     for i := 1 to NumChoices do
  383.     begin
  384.         if (BestUse[i]) then
  385.         begin
  386.             CostLabel[i].Font.Color := clWhite;
  387.             CostLabel[i].Color := clBlack;
  388.             ProfitLabel[i].Font.Color := clWhite;
  389.             ProfitLabel[i].Color := clBlack;
  390.         end;
  391.     end;
  392.  
  393.     // Calculate the best solution's cost.
  394.     best_cost := 0;
  395.     for i := 1 to NumChoices do
  396.         if (BestUse[i]) then best_cost := best_cost + Cost[i];
  397.  
  398.     // Show the total cost and profit.
  399.     TotalCostLabel.Caption := Format('%d', [best_cost]);
  400.     TotalProfitLabel.Caption := Format('%d', [BestProfit]);
  401.     NodesVisitedLabel.Caption := Format('%d', [NodesVisited]);
  402. end;
  403.  
  404. procedure TDecideForm.ResetSolution;
  405. var
  406.     i : Integer;
  407. begin
  408.     // Blank the result strings.
  409.     TotalCostLabel.Caption := '';
  410.     TotalProfitLabel.Caption := '';
  411.     NodesVisitedLabel.Caption := '';
  412.     Application.ProcessMessages;
  413.  
  414.     // Reset algorithm variables.
  415.     TestProfit := 0;
  416.     TestCost := 0;
  417.     BestProfit := 0;
  418.     NodesVisited := 0;
  419.  
  420.     // See how much money is available.
  421.     CostAvailable := StrToInt(MaxAvailableText.Text);
  422.  
  423.     // See how much profit is possible.
  424.     UnusedProfit := 0;
  425.     for i := 1 to NumChoices do
  426.     begin
  427.         UnusedProfit := UnusedProfit + Profit[i];
  428.         BestUse[i] := False;
  429.     end;
  430.  
  431.     for i := 1 to MAX_CHOICES do
  432.     begin
  433.         CostLabel[i].Font.Color := clBlack;
  434.         CostLabel[i].Color := clBtnFace;
  435.         ProfitLabel[i].Font.Color := clBlack;
  436.         ProfitLabel[i].Color := clBtnFace;
  437.     end;
  438. end;
  439.  
  440. procedure TDecideForm.DisableSearch(Sender: TObject);
  441. begin
  442.     CmdSearch.Enabled := False;
  443. end;
  444.  
  445. procedure TDecideForm.mnuExitClick(Sender: TObject);
  446. begin
  447.     Close;
  448. end;
  449.  
  450. end.
  451.