【发布时间】:2020-06-19 22:25:26
【问题描述】:
所以在个人 C++ 项目中,我遇到了一个问题。我将其改写如下:
给定一个由 n 个元素组成的数组(例如 [1, 3, 5],其中 n = 3 个元素),其中第 i 个位置的数字表示有多少第 i 个索引处的数字可以取的可能值(例如,这里第一个元素可以取 1 个值,即 0;第二个元素可以取 0、1、2 中的 3 个值;第三个元素可以从 0,1,2,3,4) 中取 5 个值。
我需要列出所有可能的长度为 n 且总和小于或等于给定数字 k 的数组。 这是一个例子:
输入 1:
输入数组 = [2,2]; k = 2
输出 1:
[0,0], [0,1], [1,0], [1,1]
还有,例如:
输入 2:
输入数组 = [2,2]; k = 1
输出 2:
[0,0], [0,1], [1,0]
问题:
我编写了一个简单的递归和简单的迭代解决方案,它会枚举所有数组,只保留总和小于 k 的数组。这些问题在于,对于 n 很大且 k = 1 的情况,我的代码需要很长时间才能运行,因为它会枚举所有情况并保留一些情况。
我看不到任何重叠的子问题,所以我觉得 DP 和 memoization 不适用。我怎样才能为此编写所需的 C++ 代码?
这是我的迭代版本代码:
// enumerates all arrays which sum up to k
vector<vector<int> > count_all_arrays(vector<int> input_array, int k){
vector<vector<int> > arr;
int n = (int)input_array.size();
// make auxilliary array with elements
for(int i = 0; i < n; i++){
vector<int> temp(input_array[i]);
std::iota(temp.begin(), temp.end(), 0);
arr.push_back(temp);
}
// computes combinations
vector<int> temp(n);
vector<vector<int> > answers;
vector<int> indices(n, 0);
int next;
while(1){
temp.clear();
for (int i = 0; i < n; i++)
temp.push_back(arr[i][indices[i]]);
long long int total = accumulate(temp.begin(), temp.end(), 0);
if(total <= k)
answers.push_back(temp);
next = n - 1;
while (next >= 0 &&
(indices[next] + 1 >= (int)arr[next].size()))
next--;
if (next < 0)
break;
indices[next]++;
for (int i = next + 1; i < n; i++)
indices[i] = 0;
}
return answers;
}
【问题讨论】:
-
你能发布递归版本吗?这可能会更容易优化。
-
DP 似乎适用。考虑 k=14 的 [6,6,6,6]。部分解决方案 [4,3,x,x] 和 [2,5,x,x] 都导致 k=7 的子问题 [6,6]。
-
@user3386109 如果 OP 只需要计算此类数组的总数,那么您可以 DP,但如果他们需要实际枚举所有数组,那么使用递归和一些简单的检查可能是最简单的防止生成无效数组。
-
@BessieTheCow 我丢失了大约 200 个文件中的递归版本,但大致如下:geeksforgeeks.org/combinations-with-repetitions
-
@user3386109 我确实需要明确列出所有这样的数组,是的:(
标签: c++ arrays algorithm dynamic-programming counting