分支定界法

来源:互联网 发布:js注释快捷键无效 编辑:程序博客网 时间:2024/05/09 14:30
分支定界法的思想是:首先确定目标值的上下界,边搜索边减掉搜索树的某些支,提高搜索效率。

原文见:http://it.pjschool.com.cn/Article/ArticleShow.asp?ArticleID=231

例1:设有A,B,C,D,E 5人从事j1,j2,j3,j4,j5 5项工作每人只能从事一项,它们的

效益表如下:

  j1 j2 j3 j4 j5 A 13 11 10 4 7 B 13 10 10 8 5 C 5 9 7 7 4 D 15 12 10 11 5 E 10 11 8 8 4

求最佳安排,使效益最高?

 

原文代码重写如下,希望增加点可读性。

 

program PlanJob;

const MAX_SIZE = 20;

type
  TIntArray = array[1..MAX_SIZE] of Integer;
  PNode = ^Node;
  Node = record
    Job2Man: TIntArray;     // Job2Man[n] = m, job-n assign to person-m
    Man2Job: TIntArray;    // Man2Job[n] = m, person-n assign to job-m
    UpperVal: Integer; // upper value
    JobsDep: Integer;   // jobs decided, as search depth
    Next: PNode;
  end;

var
   CurNode: PNode;      // Current node
   NewNode: PNode;      // New branch node
   DelNode: PNode;      // for delete
   GoalNode: PNode;     // the goal
   GoalMaxVal: Integer; // goal max value
   CurMan, CurJob: Integer;     // Current Man and Job of current Node

   Size: Integer;       // Person number, also task number
   Values: array[1..MAX_SIZE, 1..MAX_SIZE] of Integer;

function CalUpperValue(ANode: PNode): Integer;
var
  Res: Integer;
  Man, Job: Integer;
  JobMaxVal: Integer;
begin
  Res := 0;
  with ANode^ do
  begin
    for Job := 1 to Size do
    begin
      if Job <= JobsDep then
      begin
        Man := Job2Man[Job];
        Res := Res + Values[Man, Job];
        Continue;
      end;

      // else find the max value for Job
      JobMaxVal := 0;
      for Man := 1 to Size do
      begin
        if (JobMaxVal < Values[Man,Job]) and (Man2Job[Man] = 0) then
          JobMaxVal := Values[Man,Job];
      end;
      Res := Res + JobMaxVal;
    end;    // for Job
  end;    // with ANode^
  CalUpperValue := Res;
end;

function InitNode(): PNode;
var
  Man, Job: Integer;
  FInput: Text;
  Res: PNode;
begin
  Assign(FInput, 'input.txt');
  Reset(FInput);
  Read(FInput, Size);
  Readln(FInput);
  for Man := 1 to Size do
  begin
    for Job := 1 to Size do
      Read(FInput, Values[Man,Job]);
    Readln(FInput);
  end;

  New(Res);
  with Res^ do
  begin
    for Man := 1 to Size do
    begin
      Man2Job[Man] := 0;
      Job2Man[Man] := 0;
    end;
    JobsDep := 0;
    UpperVal := CalUpperValue(Res);
    Next := nil;
  end;
  InitNode := Res;
end;

procedure Insert(ANode: PNode; From: PNode);
var
  PrevNode, NextNode: PNode;
begin
  NextNode := From;
  repeat
    PrevNode := NextNode;
    NextNode := PrevNode^.Next;
  until (NextNode = nil) or (ANode^.UpperVal >= NextNode^.UpperVal);
  PrevNode^.Next := ANode;
  ANode^.Next := NextNode;
end;

procedure PrintNode(ANode: PNode);
var
  Man, Job: Integer;
  AllJobAssigned: Boolean;
begin
  AllJobAssigned := true;
  for Job := 1 to Size do
  begin
    Man := ANode^.Job2Man[Job];
    if 0 <> Man then
      Writeln('Job ', Job, ' assign to man ',
        Man, ', value ', Values[Man, Job])
    else
      AllJobAssigned := false;
  end;
  Writeln;
  if AllJobAssigned then
    Writeln('Value = ', ANode^.UpperVal)
  else
    Writeln('UpperVal = ', ANode^.UpperVal);
end;

begin
  CurNode := InitNode();
  GoalMaxVal := 0;

  repeat
    CurJob := CurNode^.JobsDep + 1;
    for CurMan := 1 to Size do
    begin
      if CurNode^.Man2Job[CurMan] <> 0 then
        Continue;

      // New search branch
      New(NewNode);
      NewNode^ := CurNode^;
      NewNode^.JobsDep := CurJob;
      NewNode^.Man2Job[CurMan] := CurJob;
      NewNode^.Job2Man[CurJob] := CurMan;
      NewNode^.UpperVal := CalUpperValue(NewNode);

      if NewNode^.UpperVal < GoalMaxVal then
        Dispose(NewNode)        // discard this branch if smaller than limit
      else
        Insert(NewNode, CurNode);

      if CurJob < Size then Continue;   // for CurMan

      // all job assigned, update goal
      if NewNode^.UpperVal > GoalMaxVal then
      begin
        GoalNode := NewNode;
        GoalMaxVal := GoalNode^.UpperVal
      end;  // if
    end;    // for CurMan

    DelNode := CurNode;
    CurNode := CurNode^.Next;
    Dispose(DelNode);
  until (CurNode^.UpperVal <= GoalMaxVal)
    or (CurNode = nil);    // end of repeat

  PrintNode(GoalNode);
  Readln;
end.

 


input.txt:

5
13     11     10     4     7
13     10     10     8     5
5     9     7     7     4
15     12     10     11     5
10     11     8     8     4

output:

Job 1 assign to man 4, value 15
Job 2 assign to man 5, value 11
Job 3 assign to man 2, value 10
Job 4 assign to man 3, value 7
Job 5 assign to man 1, value 7

Value = 50


如果扩展为10*10,
input.txt:
10
13     11     10     4     7    13     11     10     4     7     
13     10     10     8     5       13     10     10     8     5     
5     9     7     7     4       5     9     7     7     4     
15     12     10     11     5       15     12     10     11     5     
10     11     8     8     4       10     11     8     8     4     
13     11     10     4     7    13     11     10     4     7     
13     10     10     8     5       13     10     10     8     5     
5     9     7     7     4       5     9     7     7     4     
15     12     10     11     5       15     12     10     11     5     
10     11     8     8     4       10     11     8     8     4     

运行约两分钟。
output :
Job 1 assign to man 9, value 15
Job 2 assign to man 5, value 11
Job 3 assign to man 2, value 10
Job 4 assign to man 8, value 7
Job 5 assign to man 6, value 7
Job 6 assign to man 4, value 15
Job 7 assign to man 10, value 11
Job 8 assign to man 7, value 10
Job 9 assign to man 3, value 7
Job 10 assign to man 1, value 7

Value = 100