找出给定整数x可以表示为唯一自然数的n次幂之和的方式的数量。
例如:如果x = 10,则n = 2。唯一可能的情况是:3 ^ 2 + 1 ^ 2
这是我在某处读到的解决方案:
int solve(int x, const vector<int> &powers, int index) {
if(index == 0) {
return (x == 1) ? 1 : 0;
}
// else
if(x == powers[index])
return 1 + solve(x, powers, index - 1);
// else
int res = 0;
res += solve(x - powers[index], powers, index - 1);
res += solve(x, powers, index - 1);
return res;
}
int main() {
int x, n;
cin >> x >> n;
int pow = 1;
vector<int> powers;
for(int a = 2; pow <= x; a++) {
powers.push_back(pow);
pow = power(a, n);
}
cout << solve(x, powers, powers.size() - 1) << endl;
return 0;
}
在这里,我无法实际想象它。如何递归思考?请解释一下解决功能?
答案 0 :(得分:4)
为了更好地理解递归,我建议你运行以下代码,它为函数调用(入口)提供可视化并返回:
#define TRACKING
#include <cmath>
#include <vector>
#include <iostream>
#ifdef TRACKING
#include <iomanip>
#include <algorithm>
const unsigned int maxOutOffset = 60U;
#endif
using namespace std;
int solve(int x, const vector<int> &powers, int index)
{
#ifdef TRACKING
int outputOffset = min(powers.size() - index, maxOutOffset);
cout << setw(outputOffset) << ">" << " entrance with index = " << index << " and x = " << x << endl;
#endif
int res = 0;
if (index == 0) {
res = (x == 1) ? 1 : 0;
}
else if (x == powers[index])
{
res = 1 + solve(x, powers, index - 1);
}
else
{
res += solve(x - powers[index], powers, index - 1);
res += solve(x, powers, index - 1);
}
#ifdef TRACKING
cout << setw(outputOffset) << "<" << " return with index = " << index << " and res = " << res << endl;
#endif
return res;
}
int main() {
int x, n;
cout << "x ? : ";
cin >> x;
cout << "n ? : ";
cin >> n;
int power = 1;
vector<int> powers;
#ifdef TRACKING
cout << "Powers privied to solve method:" << endl;
#endif
for (int a = 2; power <= x; a++) {
#ifdef TRACKING
cout << power << ", ";
#endif
powers.push_back(power);
power = pow(a, n);
}
#ifdef TRACKING
cout << endl << "Tracking the recursive solution:" << endl;
#endif
cout << "Results is "<< solve(x, powers, powers.size() - 1) << endl;
return 0;
}
使用x = 10
和n = 2
运行的结果如下:
我真的希望,提议的跟踪将帮助您理解递归并使您的解决方案更好(对应于任务)。
<强>更新强>
如果删除第一行(#define TRACKING
),则输出如下:
更新2
递归是一种借助同一功能的一些功能。例如:n! = n*(n-1)!
如果我们考虑你的特定情况(在使用求和n
的权力数组中查找/计算x
个数字的任务
任务可以表示为:
从数组中的最大数字开始,尝试使n个项目的总和为x,
其中添加下一个表示的数字 number_count_i(x)= 1 + number_count_i-1(x-item [i])
我们应该在x等于item [i]
时停止
也许,我并不是非常严格,所以试着以这样的方式思考并在纸上画画(这确实有帮助)。
答案 1 :(得分:0)
如何递归思考?
在创建MCVE的粗糙哑剧中,让我首先通过“隐藏”大多数非递归问题来“最小化”函数:
int solve(... int index)
{
if(index == 0) // termination clause
return (x == 1) ? 1 : 0; // result
// else
if(x == powers[index])
return 1 + solve(... index - 1); // recurse
// else
{
int res = 0;
res += solve(... index - 1); // recurse
res += solve(... index - 1); // recurse
return res;
}
}
注意在solve()的3次调用中,参数(在本例中为index)是如何递减的。这一行动最终会导致终止案件。
记住这种努力如何进入终止子句,现在想象一下,作为这个思想实验的一部分,每次调用“solve(index)”都会转换为一个唯一命名的函数:
solveN(), ... solve3(), solve2(), solve1(), solve0(),
其中solveK()映射到solve(K)。这种形式是一种“正常”函数调用,应该是可识别的,并且仅仅是原始递归形式的“伪装”。
(我们需要知道有多少电话?这是一个思想实验,所以,不。)
现在,让我们检查索引3的简化函数调用堆栈,直到0。要点是
solve3(...) { return (solve2(...)); }
solve2(...) { return (solve1(...)); }
solve1(...) { return (solve0(...)); }
solve0(...) { returns 0 or 1 }
foo()可能调用bar()可能会调用bric()调用brac(),这可能是正常的并且可以识别。每个函数都会完成整个工作的某些部分,每个函数都会返回,我们称之为“内部”结果,当每个函数返回给它的调用者时,它会被(可能)细化。
调用堆栈中的缩进暗示了自动变量空间的使用(在大多数hw体系结构中称为堆栈)......
摘要 - 递归调用完全就像任何函数调用一样。 N深度递归必须返回N次,并且每次返回的位置与任何正常函数返回位置完全相同,即在调用之后。
每次递归都需要至少一个终止子句。让代码不终止是错误的(即使它有一个终止子句)。
希望这有帮助。