我无法理解棘手的编程问题
首先,我要说的是,这不是作业(我是一名 A-Level 学生,这与我们解决的问题完全不同(这方式更难)),而是我遇到的一个问题。我正在努力改进我的编程逻辑。
我想到了一个场景,其中有一个随机整数数组,例如 10 个整数。用户将输入一个他想要计数的数字,算法将尝试计算出需要哪些数字来计算总和。例如,如果我想从这个整数数组中得到总和 44:
myIntegers = array(1, 5, 9, 3, 7, 12, 36, 22, 19, 63);
输出将是:
36 + 3 + 5 = 44
或者类似的东西。我希望我能说清楚。作为额外的好处,我想让算法选择尽可能少的数字来计算所需的总和,或者如果无法使用提供的数字计算总和,则给出错误。
我考虑过使用递归并迭代数组,一遍又一遍地添加数字,直到满足或超过总和。但我无法理解的是,如果算法超出总和并且需要选择性地从数组中选择哪些数字,该怎么办。
我不是在寻找完整的代码或完整的算法,我只是想听听您对我应该如何进行此操作的意见,也许还可以分享一些技巧或其他东西。我今晚可能会开始做这件事。 :P
正如我所说,不是家庭作业。只是我想做一些更高级的事情。
感谢您提供的任何帮助。 :)
First off, let me say that this is not homework (I am an A-Level student, this is nothing close to what we problem solve (this is way harder)), but more of a problem I'm trying to suss out to improve my programming logic.
I thought of a scenario where there is an array of random integers, let's for example say 10 integers. The user will input a number he wants to count to, and the algorithm will try and work out what numbers are needed to make that sum. For example if I wanted to make the sum 44 from this array of integers:
myIntegers = array(1, 5, 9, 3, 7, 12, 36, 22, 19, 63);
The output would be:
36 + 3 + 5 = 44
Or something along those lines. I hope I make myself clear. As an added bonus I would like to make the algorithm pick as few numbers as possible to make the required sum, or give out an error if the sum cannot be made with the numbers supplied.
I thought about using recursion and iterating through the array, adding numbers over and over until the sum is met or gone past. But what I can't get my head around is what to do if the algorithm goes past the sum and needs to be selective about what numbers to pick from the array.
I'm not looking for complete code, or a complete algorithm, I just want your opinions on how I should proceed with this and perhaps share a few tips or something. I'll probably start work on this tonight. :P
As I said, not homework. Just me wanting to do something a bit more advanced.
Thanks for any help you're able to offer. :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
您正在查看背包问题
编辑:您的特殊情况是 子集和问题
You are looking at the Knapsack Problem
Edit: Your special case is the Subset Sum Problem
子集和可以吗? ;]
Will subset sum do? ;]
这是经典的 Knapsack 问题,您会在大学水平算法课程中看到(或者至少我当时就看到了)。最好在纸上解决这个问题,代码中的解决方案应该相对容易解决。
编辑:需要考虑的一件事是动态编程。
This is the classic Knapsack problem that you would see in college level algorithms course (or at least I saw it then). Best to work this out on paper and the solution in code should be relatively easy to work out.
EDIT: One thing to consider is dynamic programming.
您的问题与子集和问题有关。
你必须在最坏的情况下尝试所有可能的组合。
Your Problem is related to the subset sum problem.
You have to try all possible combinations in the worst case.
恐怕这里没有捷径。除了其他人所说的,关于这是什么具体问题等之外,这里还有一些实用的建议可以为您提供一个起点:
我会对数组进行排序并给定输入总和
m
,会发现数组中第一个小于m
的数字,将其称为n
(这是总和的第一个可能的数字),并从最大可能的补码开始 (mn
),按你的方式向下工作。如果您没有找到精确匹配,请选择可用的最高值,将其命名为o
(现在是您的第二个数字),然后查找从 (mno
),然后再次向下移动。如果未找到精确匹配,请从下一个数字 n(原始 n 的索引位于索引-1 处)开始,并执行相同的操作。您可以继续这样做,直到找到两个数字的精确匹配。如果未找到两个数字之和的匹配项,请重新开始该过程,但将其扩展以包含第三个数字。等等。
这可以递归地完成。至少这种方法可以确保当您找到匹配项时,它将是形成总输入和的集合中可能数字最少的匹配项。
但有可能,最坏的情况是,你最终会经历这一切。
编辑:正如 Venr 正确指出的那样,我的第一种方法是不正确的。编辑方法以反映这一点。
No shortcuts here I'm afraid. In addition to what other people have said, about what specific problem this is etc., here's some practical advice to offer you a starting point:
I would sort the array and given the input sum
m
, would find the first number in the array less thanm
, call itn
(this is your first possible number for the sum), and start from the highest possible complement (m-n
), working your way down.If you don't find a precise match, pick the highest available, call ito
, (that now is your 2nd number) and look for the 3rd one starting from (m-n-o
) and work your way down again.If you don't find a precise match, start with the next number n (index of original n at index-1) and do the same. You can keep doing this until you find a precise match for two numbers. If no match for the sum is found for two numbers, start the process again, but expand it to include a 3rd number. And so on.
That could be done recursively. At least this approach ensures that when you find a match, it will be the one with the least possible numbers in the set forming the total input sum.
Potentially though, worst case, you end up going through the whole lot.
Edit: As Venr correctly points out, my first approach was incorrect. Edited approach to reflect this.
对于这个问题有一个非常有效的随机算法。我知道您已经接受了答案,但无论如何我很乐意分享,我只是希望人们仍然会检查这个问题:)。
这将比动态编程解决方案快得多,特别是对于随机输入。唯一的问题是,您无法可靠地检测何时没有解决方案(您可以让算法运行几秒钟,如果它没有完成,则假设没有解决方案),并且您无法确定是否会得到解决方案选择最少数量的元素。同样,您可以添加一些逻辑来使算法继续运行并尝试找到元素较少的解决方案,直到满足某些停止条件,但这会使算法变慢。但是,如果您只对有效的解决方案感兴趣,并且您有很多数字并且所需的总和可能非常大,那么这可能比 DP 算法更好。
这种方法的另一个优点是,它也适用于负数和有理数,无需任何修改,但这对于 DP 解决方案而言并非如此,因为 DP 解决方案涉及使用部分和作为数组索引,而索引只能是自然数。例如,您当然可以使用哈希表,但这会使 DP 解决方案变得更慢。
There is a very efficient randomized algorithm for this problem. I know you already accepted an answer, but I'm happy to share anyway, I just hope people will still check this question :).
This will be much faster than the dynamic programming solution, especially for random inputs. The only problems are that you cannot reliably detect when there is no solution (you could let the algorithm run for a few seconds and if it doesn't finish, assume there is no solution) and that you cannot be sure you will get the solution with minimum number of elements chosen. Again, you could add some logic to make the algorithm keep going and trying to find a solution with less elements until certain stop conditions are met, but this will make it slower. However, if you are only interested in a solution that works and you have a LOT of numbers and the desired sum can be VERY big, this is probably better than the DP algorithm.
Another advantage of this approach is that it will also work for negative and rational numbers with no modifications, which is not true for the DP solution, because the DP solution involves using partial sums as array indexes, and indexes can only be natural numbers. You can of course use hashtables for example, but that will make the DP solution even slower.
我不知道这个任务到底叫什么,但它似乎有点http://en .wikipedia.org/wiki/Knapsack_problem。
I don't know exactly what's this task is called, but it seems that it's kind of http://en.wikipedia.org/wiki/Knapsack_problem.
呵呵,我会打“不完整的规范”牌(没有人说数字不能出现多次!)并将其简化为“进行更改”问题。按降序对数字进行排序,找到第一个小于所需总和的数字,然后从总和中减去该数字(除法和余数可以加快此过程)。重复直到总和 = 0 或找不到小于总和的数字。
为了完整起见,您需要跟踪每个和中加数的数量,当然还可以通过跟踪您使用的第一个数字、跳过它并使用其他数字重复该过程来生成附加序列。这将解决 (7 + 2 + 1) 超过 (6 + 4) 的问题。
Heh, I'll play the "incomplete specification" card (nobody said that numbers couldn't appear more than once!) and reduce this to the "making change" problem. Sort your numbers in decreasing order, find the first one less than your desired sum, then subtract that from your sum (division and remainders could speed this up). Repeat until sum = 0 or no number less than the sum is found.
For completeness, you would need to keep track of the number of addends in each sum, and of course generate the additional sequences by keeping track of the first number you use, skipping that, and repeating the process with the additional numbers. This would solve the (7 + 2 + 1) over (6 + 4) problem.
重复别人的答案:这是一个子集和问题。
它可以通过动态规划技术有效地解决。
以下尚未提及:该问题是 Pseudo-P(或弱意义上的 NP-Complete)。
S(其中 S 是总和)和 n(元素数量)中的算法(基于动态规划)多项式的存在证明了这一说法。
问候。
Repeating the answer of others: it is a Subset Sum problem.
It could be efficiently solved by Dynamic Programing technique.
The following has not been mentioned yet: the problem is Pseudo-P (or NP-Complete in weak sense).
Existence of an algorithm (based on dynamic programming) polynomial in S (where S is the sum) and n (the number of elements) proves this claim.
Regards.
好吧,我写了一个C++程序来解决上面的问题。该算法很简单:-)
首先按降序排列您拥有的任何数组(我已按降序形式对数组进行了硬编码,但您可以应用任何排序算法)。
接下来我拿了三个堆栈 n、pos 和 sum。第一个存储要找到可能的总和组合的数字,第二个存储从何处开始搜索的数组索引,第三个存储元素,其相加将给出您输入的数字。
该函数查找数组中小于或等于输入数字的最大数字。如果相等,则将数字压入求和堆栈。如果没有,则将遇到的数组元素压入和栈(暂时),并查找要查找的数字与遇到的数字之间的差异,然后执行递归。
让我举个例子:-
在{63,36,22,19,12,9,7,5,3,1}中找到44,
前36将被压入总和(小于44的最大数字)
44-36=8 将被推入 n(下一个要搜索的数字)
7 将被压入总和
8-7=1 将被推入 n
1 将被推入总和
,因此 44=36+7+1 :-)
您可以复制代码并将其粘贴到您的 IDE 中,工作正常:-)
Ok, I wrote a C++ program to solve the above problem. The algorithm is simple :-)
First of all arrange whatever array you have in descending order(I have hard-coded the array in descending form but you may apply any of the sorting algorithms ).
Next I took three stacks n, pos and sum. The first one stores the number for which a possible sum combination is to be found, the second holds the index of the array from where to start the search, the third stores the elements whose addition will give you the number you enter.
The function looks for the largest number in the array which is smaller than or equal to the number entered. If it is equal, it simply pushes the number onto the sum stack. If not, then it pushes the encountered array element to the sum stack(temporarily), and finds the difference between the number to search for and number encountered, and then it performs recursion.
Let me show an example:-
to find 44 in {63,36,22,19,12,9,7,5,3,1}
first 36 will be pushed in sum(largest number less than 44)
44-36=8 will be pushed in n(next number to search for)
7 will be pushed in sum
8-7=1 will be pushed in n
1 will be pushed in sum
thus 44=36+7+1 :-)
You can copy the code and paste it in your IDE, works fine :-)