【问题标题】:Best possible combination sum of predefined numbers that smaller or equal NN小于或等于 NN 的预定义数字的最佳可能组合总和
【发布时间】:2015-08-01 17:56:40
【问题描述】:

我有一个管道长度列表,我需要将这些长度安装在最大允许长度内以获得最佳产量

例如,最大允许长度为 90,我需要制作的部分是:

25、60、13、48、23、29、27、22

为了最适合 90 以内的数字,我有一组这些数字:

60、29(共 89 个)

27、25、13、23(共 88 个)

48、22(共 70 个)

我找到this 对类似问题的回答,但我不知道如何将其转换为在 excel 或 javascript 或 php 中使用

任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 您对解决方案的复杂性有任何限制......它是否必须是 O(n) ?

标签: javascript php excel


【解决方案1】:

这是一种可能的解决方案。但它是一种蛮力算法,所以它不是尽可能快。

function bestComb(nums, target) {
  var combinations = [];
  var sums = [];
  function loop(idx, comb, sum) {
    if(idx >= nums.length || sum + nums[idx] > target) {
      combinations.push(comb.slice());
      sums.push(sum);
      return;
    }
    for(var i = idx; i < nums.length; i++) {
      if(sum + nums[i] > target) break;
      if(sum + nums[i] === target) {
        combinations.push(comb.slice());
        combinations[combinations.length - 1].push(nums[i]);
        sums.push(sum + nums[i]);
        break;
      }
      comb.push(nums[i]);
      loop(i + 1, comb, sum + nums[i]);
      comb.pop();
    }
  }

  nums = nums.slice();
  nums.sort(function(a,b) {return a - b});
  loop(0, [], 0);

  if(sums.length === 0) return null;
  var maxSum = sums[0],
      maxComb = combinations[0];
  for(var i = 1; i < sums.length; i++) {
    if(sums[i] > maxSum || sums[i] === maxSum && combinations[i].length < maxComb.length) {
      maxSum = sums[i];
      maxComb = combinations[i];
    }
  }

  return maxComb;
}

var nums = [25, 60, 13, 48, 23, 29, 27, 22];

var solution = bestComb(nums, 90);

console.log(solution);

【讨论】:

    【解决方案2】:

    这是基于 John Coleman 的 VBA 代码。它将创建一个包含所有 255 (2 8-1) 个候选者的列表,并将它们按从好到坏的顺序排列:

    Sub MAIN()
        Dim i As Long, st As String
        Dim a(1 To 8) As Integer
        Dim ary
    
        a(1) = 25
        a(2) = 60
        a(3) = 13
        a(4) = 48
        a(5) = 23
        a(6) = 29
        a(7) = 27
        a(8) = 22
    
        st = ListSubsets(a)
        ary = Split(st, vbCrLf)
    
        For i = LBound(ary) + 1 To UBound(ary) - 1
            Cells(i, 2) = Replace(ary(i + 1), " ", "")
        Next i
    
        Call DistributeData
        Call SortData
    End Sub
    
    Function ListSubsets(Items As Variant) As String
        Dim CodeVector() As Integer
        Dim i As Integer
        Dim lower As Integer, upper As Integer
        Dim SubList As String
        Dim NewSub As String
        Dim done As Boolean
        Dim OddStep As Boolean
    
        OddStep = True
        lower = LBound(Items)
        upper = UBound(Items)
    
        ReDim CodeVector(lower To upper) 'it starts all 0
        Do Until done
            'Add a new subset according to current contents
            'of CodeVector
    
            NewSub = ""
            For i = lower To upper
                If CodeVector(i) = 1 Then
                    If NewSub = "" Then
                        NewSub = Items(i)
                    Else
                        NewSub = NewSub & ", " & Items(i)
                    End If
                End If
            Next i
            If NewSub = "" Then NewSub = "{}" 'empty set
            SubList = SubList & vbCrLf & NewSub
            'now update code vector
            If OddStep Then
                'just flip first bit
                CodeVector(lower) = 1 - CodeVector(lower)
            Else
                'first locate first 1
                i = lower
                Do While CodeVector(i) <> 1
                    i = i + 1
                Loop
                'done if i = upper:
                If i = upper Then
                    done = True
                Else
                    'if not done then flip the *next* bit:
                    i = i + 1
                    CodeVector(i) = 1 - CodeVector(i)
                End If
            End If
            OddStep = Not OddStep 'toggles between even and odd steps
        Loop
        ListSubsets = SubList
    End Function
    
    Sub DistributeData()
        Columns("B:B").Select
        Selection.TextToColumns Destination:=Range("B1"), DataType:=xlDelimited, _
            TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
            Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo _
            :=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
    
            Range("A1:A255").Formula = "=if(sum(B1:I1)>=90,9999,90-sum(B1:I1))"
    End Sub
    
    Sub SortData()
        Range("A1:I255").Select
        Application.CutCopyMode = False
        ActiveWorkbook.Worksheets("Sheet5").Sort.SortFields.Clear
        ActiveWorkbook.Worksheets("Sheet5").Sort.SortFields.Add Key:=Range("A1:A255") _
            , SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
        With ActiveWorkbook.Worksheets("Sheet5").Sort
            .SetRange Range("A1:I255")
            .Header = xlGuess
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    
    End Sub
    

    所以最好的组合是:

    {60,29} 和 {25,13,​​29,22}

    参考:

    John Coleman's Code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      相关资源
      最近更新 更多