【问题标题】:Subtract until reach desired value减去直到达到所需值
【发布时间】:2012-10-17 05:52:24
【问题描述】:

大家早上好。

我目前正在尝试找出一些我相信足够简单但被证明是一项半任务才能真正解决的问题。

我正在开展一个项目,该项目旨在通过将各种文件重新定位到其他地方来最大限度地减少驱动器的使用。我有一个包含int64 值的数组(0..12),其中包含我可能想要移动的文件的文件大小。数组的排序方式是预测的最大文件大小到预测的最小文件大小。我还将这些文件的名称存储在不同的数组中(称为WoWData,也称为[0..12])。然后我得到了“安装尺寸”和“所需尺寸”。

我的任务是计算我需要移动哪些文件,以便通过遍历文件大小数组将“安装大小”降低到“所需大小”,并将值从安装大小中取出,直到我达到

这是我一直在尝试使用的一些示例代码(Delphi/Firemonkey)。试图弄清楚如何完成这样的任务让我感到困惑,因此毫无疑问会有很多问题;

Global Vars;
    _WoWDataFileSize : Array [0..12] of Int64;
    // "TBWoWDir" is a TTrackBar (Firemonkey)

var
  TotalSize, ReqSize, DiffSize, CurDiff : Int64;
  i : Integer;
begin
  // Set up initial values to work with
  ReqSize := Round(TBWoWDir.Value); // Requested Size
  TotalSize := Round(TBWoWDir.Max); // Actual installation size
  CurDiff := 0; // Assume as "Current Difference in size"

  // Calculate difference between install and requested size
  DiffSize := TotalSize - ReqSize; // This calculates correctly

// The below is what i'm struggling with
  repeat
    for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
      begin
        CurDiff := ReqSize - _WoWDataFileSize[i];
      end;
  until CurDiff <= ReqSize;
end;

我确实尝试过只使用repeat .. until 循环而不使用for 循环,但同样,我在试图弄清楚它时变得太困惑了。


让我举个例子。假设_WoWDataFileSize[0] 为200,_WoWDataFileSize[1]_WoWDataFileSize[12] 的值与其数组索引相同(例如_WoWDataFileSize[6] = 6、_WoWDataFileSize[8] = 8 等)。

如果我想计算 150 的值(根据数组将是 200 - 12 - 11 - 10 - 9 - 8Array[0] - Array[12] - Array[11] - Array[10] - Array[9] - Array[8]),并从 WoWData 数组中获取我需要移动以满足此要求的文件列表,我将如何编写例程?

150 可以替换为任何数字,因为我正在努力实现TBWoWDir.Value 指定的动态用户请求大小。

我想我可能需要做一个While 循环并使用i := i+1 设置。实际上,我可以通过并对其进行硬编码,以便一次取出数组中的一个值,并每次检查我是否

【问题讨论】:

  • 听起来您正在研究bin-packing problem 的解决方案,以使文件适合最少数量的安装媒体。样本近似实现在在线和介绍性算法教科书中很常见。这是一个NP-hard问题,但只有13个文件,运行时间应该不会太差。

标签: delphi math


【解决方案1】:
curdiff:= 0;
i:= Low(_WoWDataFileSize) - 1;
while (curdiff <= reqsize) and (i < High(_WoWDataFileSize)) do
 begin
  inc (i);
  curdiff:= curdiff + _WoWDataFileSize[i];
 end;

在循环结束时,您已经达到了所需的大小缩减,或者您已经遍历了整个数组。

【讨论】:

    【解决方案2】:

    恕我直言,您的代码中仅缺少两行 :o)

    CurDiff := ReqSize;
    // repeat
      for i := Low(_WoWDataFileSize) to High(_WoWDataFileSize) do
        begin
          CurDiff := CurrDiff - _WoWDataFileSize[i];
          if CurDiff <= ReqSize then break; // breaks the for..to loop
        end;
    // until CurDiff <= ReqSize;
    

    编辑不需要重复...直到循环

    但是恕我直言,仅计算大小而不存储匹配的文件并不是很有用。 因此,使用 CustomObject 和 Lists(感谢 Generics)将非常简单:

    type
      TFileObject = class
      private
        FName : string;
        FSize : Int64;
      public
        constructor Create( AName : string; ASize : Int64 );
      published
        property Name : string read FName;
        property Size : Int64 read FSize;
      end;
    
    procedure MoveFileObject(AMaxSize : Int64; ASrcList, ATarList : TList<TFileObject> );
    var
      LItem : TFileObject;
      LSize : Int64;
    begin
      LSize := 0;
      for LItem in ASrcList do
      begin
        if LSize + LItem.Size <= AMaxSize then
          begin
            LSize := LSize + LItem.Size;
            ATarList.Add( LItem );
          end;
      end;
    end;
    

    【讨论】:

    • 对于您的Break 声明,您从repeatuntil 的话中感受到了什么?此外,还有repeat/until 循环,然后是for 循环;当您使用 Break 语句时,请尝试考虑是否仅使用其中一个还不够。
    • @TLama 是的,你是对的 :o) 但完全不清楚,这个结果将如何帮助决定应该复制哪些文件
    【解决方案3】:

    感谢大家的回答,我知道我哪里出错了。当我在最初的问题中进行计算时,我忘记考虑我对值的划分(为了显示 MB 而不是字节,因为TBWoWDir.Value 被实时绑定到TLabel.text,但实际大小正在被划分在分配TBWoWDir.Max之前)。

    感谢 No'am Newman 的回答中的一些调整,我设法自己解决了这个问题。这就是我得到我想要的结果的方式(或者更接近它);

    Global Vars;
        _WoWDataFileSize : Array [0..12] of Int64;
    Global Const;
        _WoWData : Array [0..12] of String;
        // "TBWoWDir" is a TTrackBar (Firemonkey)
    
    [...]
    var
      ReqSize : int64;
      DiffSize, CurDiff : Int64;
      i, ii : Integer;
      FilesTot : Integer;
      FILESMSG : String;
    begin
      // Set up initial values to work with
      ReqSize := Round(TBWoWDir.Value) * 1024 * 1024; // Requested Size - Multiplied from formatting
      TotalSize := Round(TBWoWDir.Max) * 1024 * 1024; // Actual installation size - Multiplied from formatting
    
      DiffSize := TotalSize - ReqSize; // Calculate Difference
      CurDiff := 0; // Reset Current Difference
      i := -1; // Reset i
      repeat
        inc (i); // Increment i
        CurDiff := CurDiff + _WoWDataFileSize[i]; // Add current array item file size to CurDiff
      until (CurDiff >= (DiffSize)) or (i >= 12); // Repeat until we reach ideal size or the end of the array
    
      // Calculate which array item we stopped at
      for ii := 0 to i do // use i from previous loop as the max
      begin
        FILESMSG := FILESMSG + 'File: ' + WoWData[ii] +
                               ' | Size: ' + IntToStr(_WoWDataFileSize[ii])+' '#13#10;
        FilesTot := FilesTot + _WoWDataFileSize[ii];
      end;
    
      // Show Message providing details
      ShowMessage('CurDiff:' + IntToStr(CurDiff div 1024 div 1024) +
                  ' | DiffSize: ' + IntToStr(DiffSize div 1024 div 1024) +
                  ' | Array i: ' +
                  IntToStr(i) +#13#10+
                  'Difference between CurDiff and DiffSize: '+ IntToStr(((DiffSize div 1024 div 1024) - (CurDiff div 1024 div 1024)))+#13#10#13#10+
                  'File Details' +#13#10#13#10+
                  FilesMsg +#13#10#13#10+
                  'Total Size: ' + IntToStr(FilesTot));
    end;
    

    那里的代码告诉我我需要复制哪些文件(因此现在修改它以复制文件并不太难),整个ShowMessage 用于自我证明(因为我使用@987654326 @ 在开发过程中,当我需要验证一个值是否正确返回时,我相信许多其他人也会这样做)。

    【讨论】:

      猜你喜欢
      • 2021-06-20
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 2020-04-20
      • 1970-01-01
      相关资源
      最近更新 更多