【发布时间】:2021-06-30 05:24:39
【问题描述】:
假设我有一个给定的总和,比如 sum = 4。我还得到一个向量 = {2,4}。有两种方法可以从给定的向量生成给定的总和(可以重复使用元素)。 一种方法就是 {4} 导致 4 = 4。 第二种方法是 {2,2} 导致 2 + 2 = 4。 我必须找到可能的最短组合,因此在这种特殊情况下,答案是 {4}。
这是我的方法 - 我遍历树,当在叶子上得到 0 时,我们达到基本情况,返回 {} 向量,并在遍历树时填充向量。当我到达一个节点时,我选择两个(或更多)向量中较小的一个。这样当我到达根节点时,我应该得到一个可以产生目标总和的最短组合的向量。
到目前为止,我并不关心时间限制,我知道有很多重复的计算正在进行,所以一旦我能够正确地获得基本版本,我就必须记住它。
我一直在试图弄清楚为什么这段代码不起作用。任何见解将不胜感激。
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> findBestSum(int targetSum, const vector<int> &elements, vector<vector<int>> &temp) {
if (targetSum == 0)
return {};
else if (targetSum < 0)
return {-1};
else {
vector<int> small;
for (auto &i : elements) {
int remainder = targetSum - i;
vector<int> returnedVector = findBestSum(remainder, elements, temp);
if ((!returnedVector.empty() && find(returnedVector.begin(), returnedVector.end(), -1) == returnedVector.end()) || returnedVector.empty()) {
returnedVector.push_back(i);
temp.push_back(returnedVector);
}
int smallestLength = temp[0].size();
for (auto &j : temp)
if (smallestLength >= j.size())
small = j;
}
return small;
}
}
int main() {
int targetSum = 6;
const vector<int> elements{2, 3, 5}; // answer should be [3,3] however I just get a 3...
vector<vector<int>> temp;
vector<int> bestSumVector = findBestSum(targetSum, elements, temp);
for (auto i : bestSumVector)
cout << i << " ";
}
更新(2021 年 7 月 14 日):
在忙碌了几个月后,我试图解决这个问题,这次我的代码如下所示:
#include <iostream>
#include <vector>
#include <map>
#include <numeric>
using namespace std;
bool howSum(int &targetSum, vector<int> &elementVector, vector<int> &howSumVector, vector<vector<int>> &allSums) {
static int originaltargetsum = targetSum;
if (targetSum == 0)
return true;
else if (targetSum < 0)
return false;
else {
for (auto i : elementVector) {
int remainder = targetSum - i;
bool flag = howSum(remainder, elementVector, howSumVector, allSums);
if (flag) {
howSumVector.push_back(i);
if (targetSum == originaltargetsum ||
accumulate(howSumVector.begin(), howSumVector.end(), 0) == originaltargetsum) {
allSums.push_back(howSumVector);
howSumVector.clear();
}
return true;
}
}
return false;
}
}
int main() {
int sum = 8;
vector<int> elements = {1, 4, 5};
vector<vector<int>> allSums = {};
vector<int> workingBench = {};
howSum(sum, elements, workingBench, allSums);
for (auto &i : allSums) {
for (auto &j : i) {
cout << j << " ";
}
cout << endl;
}
}
为此,我将sum 设置为8,将elements 设置为{1, 4, 5}。
此外,我现在正在存储和显示所有可能的解决方案(一旦正确完成,找到最短向量和记忆应该很容易)。在这种情况下可能的解决方案是:
[1, 1, 1, 1, 1, 1, 1, 1]
[4, 4]
[5, 1, 1, 1]
[4, 1, 1, 1, 1]
目前我的代码只显示第一个可能的组合。我很确定我错误地返回了true 和false,请在这里帮帮我。
【问题讨论】:
-
好吧,我并没有真正看到任何将某些东西推送到
small的东西,只有small = j对其进行了修改,所以这可能就是为什么你只得到3作为输出的原因。尝试调试它。 -
small = j复制最小的j的内容(我的向量向量中的最小向量),这就是我没有使用push_back(...)或其他任何东西的原因。 -
通过调试代码我可以看到
j实际上确实具有temp中的最小向量。问题在于将i推回returnedVector,然后将returnedVector推回temp。 -
一旦对
howSum的调用返回true,它们将all 返回true,并且您只会将一个元素添加到结果数组中。我认为您在进行递归调用时会希望在howSum中添加和删除元素,因为(以您的示例)在添加[4, 1, 1, 1, 1]之后,您需要在再次递归尝试时将4保留在howSum中elementVector(4) 中的下一个元素。
标签: c++ recursion dynamic-programming subset-sum