【问题标题】:Find all the combinations that return a particular value from a function查找从函数返回特定值的所有组合
【发布时间】:2020-04-26 00:18:36
【问题描述】:

这是查找添加到目标的所有组合的变体,有两个约束:

  • 我们可以使用的数字有限。
  • 输入单独的函数时,数字必须生成目标数字。

在这种情况下,有限的一组数字包括 25、50、100、200、450、700、1100、1800、2300、2900、3900、5000、5900、7200、8400 等。

函数是将这些值相加,然后根据我们有多少个数字乘以一个数字:

  • 如果是 1 个数字,则乘以 1。
  • 如果是 2 个数字,则乘以 1.5
  • 如果是 3-6 个数字,乘以 2
  • 如果是 7-10 个数字,乘以 2.5
  • 如果 >10 个数字,则乘以 3

例子:

[50, 50, 50] => 300

[100, 100] => 300

目标数字包括300、600、900、1500、3000、3600、4400、5600、6400、7600、9600等

我的直觉是这不能递归完成,因为每一步都不知道最终会应用的乘数。

【问题讨论】:

  • 我的方法将是一个动态编程解决方案,其中 DP[X][Y] = 我们是否可以使用 X 数对 Y 求和。例如,DP[75][2] 为真,因为我们可以通过将 50 和 25 相加得到 75。从这个“原始总和”中,您可以通过乘以乘数来计算调整后的总和(调整后的总和为 75 * 1.5)。 DP 递归将是 DP[X][Y] = Ǝ(DP[X-n][Y-1] for all n in the limited set of numbers)。还没有完全考虑清楚,可能会有额外的并发症,但这就是我开始解决问题的方式。
  • 我想这取决于数字的范围。如果 Sum(Numbers) * Count(Numbers) 可以存储在内存中,那么 Memoization 方法将是可行的。
  • 像硬币兑换问题这样的解决方案,但每次计数进入新范围时都可以缩放总和?
  • 有28个数字,19个目标。

标签: algorithm


【解决方案1】:

这是一个似乎满足要求的 JavaScript 递归示例:

function getNextM(m, n){
  if (n == 1)
    return 1.5;
  if (n == 2)
    return 2;
  if (n == 6)
    return 2.5;
  if (n == 10)
    return 3;

  return m;
}

function g(A, t, i, sum, m, comb){
  if (sum * m == t)
    return [comb];
    
  if (sum * m > t || i == A.length)
    return [];
    
  let n = comb.length;
    
  let result = g(A, t, i + 1, sum, m, comb);
  
  const max = Math.ceil((t - sum) / A[i]);

  let _comb = comb;
  
  for (let j=1; j<=max; j++){
    _comb = _comb.slice().concat(A[i]);
    sum = sum + A[i];
    m = getNextM(m, n);
    n = n + 1;
    result = result.concat(g(
      A, t, i + 1, sum, m, _comb)); 
  }
  
  return result;
}

function f(A, t){
  return g(A, t, 0, 0, 1, []);
}


var A = [25, 50, 100, 200, 450, 700, 1100, 1800, 2300, 2900, 3900, 5000, 5900, 7200, 8400];

var t = 300;

console.log(JSON.stringify(f(A, t)));

  

【讨论】:

  • 像魅力一样工作!
【解决方案2】:

我用 Python3 写了一个小脚本可以解决这个问题。

multiply_factor = [0,1,1.5,2,2,2,2,2.5,2.5,2.5,2.5,3]
def get_multiply_factor(x):
    if x< len(multiply_factor):
        return multiply_factor[x]
    else:
        return multiply_factor[-1]


numbers = [25, 50, 100, 200, 450, 700, 1100, 1800, 2300, 2900, 3900, 5000, 5900, 7200, 8400]
count_of_numbers = len(numbers)


# dp[Count_of_Numbers]
dp = [[] for j in range(count_of_numbers+1)]

#Stores multiplying_factor * sum of numbers for each unique Count, See further
sum_found =[set() for j in range(count_of_numbers+1)]

# Stores Results in Unordered_Map for answering Queries
master_record={}

#Initializing Memoization Array
for num in numbers:
    dp[1].append(([num],num*get_multiply_factor(1)))

for count in range(2,count_of_numbers+1):   # Count of Numbers
    for num in numbers:
        for previous_val in dp[count-1]:
            old_factor = get_multiply_factor(count-1)   #Old Factor for Count Of Numbers = count-1
            new_factor = get_multiply_factor(count)     #New Factor for Count Of Numbers = count

            # Multiplying Factor does not change
            if old_factor==new_factor:
                # Scale Current Number and add
                new_sum = num*new_factor+previous_val[1]
            else:
                #Otherwise, We rescale the entire sum
                new_sum = (num+previous_val[1]//old_factor)*new_factor

            # Check if NEW SUM has already been found for this Count of Numbers
            if new_sum not in sum_found[count]:
                # Add to current Count Array
                dp[count].append(([num]+previous_val[0],new_sum))
                # Mark New Sum as Found for Count Of Numbers = count
                sum_found[count].add(new_sum)
                if new_sum not in master_record:
                    # Store Seected Numbers in Master Record for Answering Queries
                    master_record[new_sum] = dp[count][-1][0]



# for i in dp:
#   print(i)
print(master_record[1300])
print(master_record[300])
print(master_record[2300])
print(master_record[7950])
print(master_record[350700.0])

输出:-

[100, 100, 450]
[100, 100]
[25, 25, 1100]
[25, 50, 3900]
[1800, 5900, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400, 8400]
[Finished in 0.3s]

简而言之我的算法。

Iterate over Count[2, Limit], I've considered limit = Number of Elements
    Iterate over List of Numbers
        Iterate over Sums found for previous count.
            Calculate New Sum,
            If it does not exist for current count, update.

我假设查询的数量会很大,以便记忆得到回报。计数的上限可能会破坏我的代码,因为可能性可能会呈指数增长。

【讨论】:

  • master_record[300] 的结果应该是[[100, 100], [25, 25, 100], [50, 50, 50], [25, 25, 50, 50], [25, 25, 25, 25, 50], [25, 25, 25, 25, 25, 25]] 你能澄清一下这个算法是否可以做到这一点?
  • 不,不能抱歉。您正在寻找所有可能的方法来找到所需的金额?
  • 是的。优化的一种想法是将数字列表截断为仅低于目标的数字。我们也可以先尝试最小的数字,只是为了得到最大的数组大小,即使算​​法的其余部分从最高的开始。
猜你喜欢
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
  • 1970-01-01
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多