分支定界之深度搜索定界

深度搜索定界

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

原文题为分支定界, 深度搜索定界是其中例2,
例1代码已重写为 http://blog.csdn.net/jq0123/archive/2006/05/30/762957.aspx
此为例2代码重写.

根据 http://www.skyheart.com.cn/html/DATASTRUCTE/20060528103723307.htm
分支定界 (branch and bound) 算法是一种在问题的解空间树上搜索问题的解的方法。但与回溯算法不同,分支定界算法采用广度优先或最小耗费优先的方法搜索解空间树,并且,在分支定界算法中,每一个活结点只有一次机会成为扩展结点。
些例不算是分支定界算法, 而是回溯算法, 应用了限界函数( bounding function)来定界.

原代码对于如下数据输出为27,错误。
3  12
11 7 5  5  4 7
11 7 5  5  4 7

输出应为
11 11 4
7 7 7 5
7 5 5 5 4
Time=26

{
http://it.pjschool.com.cn/Article/ArticleShow.asp?ArticleID=231

分支定界法的思想是:首先确定目标值的上下界,边搜索边减掉搜索树的某些支,提高搜索效率。

2. 2 深度搜索定界

例2:设定有n台处理机p1,p2,......pn,和m个作业j1,j2,...jm,处理机可并行工作,作业未完成不能中断,作业ji在处理机上的处理时间为ti,求解最佳方案,使得完成m项工作的时间最短?

说明:本题有两重搜索法,搜索处理机和搜索作业,当m,n较大时,搜索处理机不可能?搜索作业容易确定上下界,容易剪支。

若输入文件是:

3  6
11 7 5  5  4 7

输出结果如下:

7 7

5 5 4

11

time=14 

}
program Jobs;

const
  MAXN = 100;
  MAXM = 1000;

var
  JobReqTime: array[1..MAXM] of Integer;

  // jobs count on processor-I
  JobNums, BestJobNums: array[1..MAXN] of Integer;

  // TimeBlocks[Proc, Seq]: the Seq block time of Proc
  // TimeBlocks[2, 4] = 12 means processor-2's 4th job requires 12 time.
  TimeBlocks, BestTmBlocks: array[1..MAXN, 1..MAXM] of Integer;

  MaxTimeTotal: Integer;        // = ProcUsedTime[1]
  ProcUsedTime: array[1..MAXN] of Integer;
  JobDone: array[1..MAXM] of Boolean;
  Least: Integer;
  I, J: Integer;
  FreeProc: Integer;
  ProcNum, JobNum: Integer;     // Number of Processors and Jobs
  Rest: Integer;

procedure print;
var
  I, J: Integer;
begin
  for I := 1 to ProcNum do
  begin
    for J := 1 to BestJobNums[I] do
      Write(BestTmBlocks[I, J], ' ');
    Writeln;
  end ;
  Writeln('Time=', MaxTimeTotal);
end;

procedure InitReadParams;
var
  F: Text;
  I, J: Integer;
  temp: Integer;
begin
  Assign(F, 'input.txt');
  Reset(F);
  Readln(F, ProcNum, JobNum);
  Rest := 0;
  for I := 1 to JobNum do
  begin
    Read(F, JobReqTime[I]);
    Inc(Rest, JobReqTime[I]);
  end;
  Close(F);

  Least := Trunc(Rest div ProcNum); { 确定下界 }

  // Sort requested times, decsending.
  for I := 1 to JobNum - 1 do
    for J := I + 1 to JobNum do
      if JobReqTime[I] < JobReqTime[J] then
      begin
        temp := JobReqTime[I];
        JobReqTime[I] := JobReqTime[J];
        JobReqTime[J] := temp;
      end;
end;

{
Processor can reject job if required time too much.
1. ProcUsedTime[] should less than MaxTimeTotal
2. ProcUsedTime[] should not ascend
}
function ProcRejectJob(AProc, AJob: Integer): Boolean;
var
  NewUsedTime: Integer;
begin
  NewUsedTime := ProcUsedTime[AProc] + JobReqTime[AJob];
  if 1 = AProc then
    ProcRejectJob := NewUsedTime >= MaxTimeTotal
  else
    ProcRejectJob := NewUsedTime > ProcUsedTime[AProc - 1];
end;

procedure AddJobToProc(AJob, AProc: Integer);
begin
      Inc(JobNums[AProc]);
      TimeBlocks[AProc, JobNums[AProc]] := JobReqTime[AJob];
      Inc(ProcUsedTime[AProc], JobReqTime[AJob]);
      Dec(Rest, JobReqTime[AJob]);
end;

procedure RemoveJobFromProc(AJob, AProc: Integer);
begin
      Dec(JobNums[AProc]);
      Dec(ProcUsedTime[AProc], JobReqTime[AJob]);
      Inc(Rest, JobReqTime[AJob]);
end;

{ 从AJob..JobNum中选取作业放在处理机AProc上 }
procedure SearchFrom(AJob, AProc: Integer);
var
  I: Integer;
begin
  if MaxTimeTotal = Least then Exit;

  for I := AJob to JobNum do
  begin
    if JobDone[I] then Continue;
    if ProcRejectJob(AProc, I) then Continue;

    JobDone[I] := True;
    AddJobToProc(I, AProc);
    // try to add more jobs
    SearchFrom(I + 1, AProc);
    RemoveJobFromProc(I, AProc);
    JobDone[I] := False;
  end;  // for I

  if Rest = 0 then
  begin
      BestJobNums := JobNums;
      BestTmBlocks := TimeBlocks;
      MaxTimeTotal := ProcUsedTime[1];  // ProcUsedTime[1] is always the largest
  end
  else if Rest > (ProcNum - AProc) * ProcUsedTime[AProc] then
    Exit       // stop this search branch
  else if AProc < ProcNum then
    SearchFrom(1, AProc + 1);

end;

begin
  InitReadParams;

  { 确定上界 }
  FillChar(ProcUsedTime, SizeOf(ProcUsedTime), 0);
  FillChar(BestTmBlocks, SizeOf(BestTmBlocks), 0);
  FillChar(BestJobNums, SizeOf(BestJobNums), 0);
  for I := 1 to JobNum do
  begin
    // find the most free proccessor
    FreeProc := 1;
    for J := 2 to ProcNum do
      if ProcUsedTime[J] < ProcUsedTime[FreeProc] then FreeProc := J;

    // assign job-I to most free proc
    ProcUsedTime[FreeProc] := ProcUsedTime[FreeProc] + JobReqTime[I];
    BestJobNums[FreeProc] := BestJobNums[FreeProc] + 1;
    BestTmBlocks[FreeProc, BestJobNums[FreeProc]] := JobReqTime[I];
  end;

  MaxTimeTotal := 0;
  for I := 1 to ProcNum do
    if ProcUsedTime[I] > MaxTimeTotal then
      MaxTimeTotal := ProcUsedTime[I];

  // start to search
  FillChar(JobDone, SizeOf(JobDone), False);
  FillChar(ProcUsedTime, SizeOf(ProcUsedTime), 0);
  FillChar(TimeBlocks, SizeOf(TimeBlocks), 0);
  FillChar(JobNums, SizeOf(JobNums), 0);
  SearchFrom(1, 1);

  print;
  ReadLn;
end.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值