我正在创建一个程序,它只返回使用1,2,6和13来获得数字(n)所需的最小数量。它适用于n的小值,但是一旦得到n对于像200这样的值,程序需要花费太多时间来计算结果。
因此,我有两个问题:
1。有没有办法让递归更快?
2. 我应该避免使用递归并改为使用循环吗?
以下是注释代码:
#include <iostream>
#define MAX 500000
using namespace std;
void cal(int inp, int &mini, int counter = 0);
int main (void)
{
//Gets input
int n;
cin >> n;
//Defines mini as the MAX result we can get
int mini = MAX;
//Calls the function
cal(n, mini);
//Prints the best result
cout << mini << endl;
return 0;
}
void cal(int inp, int &mini, int counter)
{
//Breaks recursion if it finds an answer
if(!inp)
{
if(counter<mini) mini = counter;
return;
}
//Breaks recursion if the input is negative
//or the counter is more than the best result
else if((inp<0) || (counter>mini)) return;
//Counts amount of recursions
counter++;
//Tries every combination
cal(inp-13, mini, counter);
cal(inp-6, mini, counter);
cal(inp-2, mini, counter);
cal(inp-1, mini, counter);
return;
}
谢谢
答案 0 :(得分:4)
问题在于你的暴力。让我提出更好的建议:
预备:如果你有两个1,最好使用2个。如果你有3个2,最好使用6个。如果你有13个6s,最好使用6个12个。
所以任何可以接受的总和总是看起来像n = 13m+k
,其中k
被写为1,2和6的总和。通过预备,我们知道最佳总和{{1永远不会超过k
。 (相反的情况并不成立。当然,没有任何低于78的数字最好在没有13s的情况下写出来。)所以粗暴强迫这些就足够了。然后,您可以使用查找表。
这仍然可以进一步优化,但它不应该在200下降。
假设您找到了前77个条目(也可以进行优化),您可以这样做(仍未优化; - ):
1+2*2+12*6 = 77
我甚至可以更快地为等价类modulo 13编译数组,因为对于任何给定的等价类,任何超过78的数字都将具有相同的int num_13 = ((n-78) / 13) + 1;
int sum_length = MAX;
for (i = num_13; i*13 < n; i++) {
int tmp = entries_77[n-i*13]+i;
if (tmp < sum_length) {
num_13 = i;
sum_length = tmp;
}
}
。
答案 1 :(得分:4)
您可以使用DP(动态编程)方法来解决您的问题。众所周知Coins Problem
答案 2 :(得分:1)
您的递归需要记忆以避免重复计算。并且不需要递归的第二个和第三个参数。我已经更新并对您的代码进行了解释。如果你有任何困惑,请告诉我。
llo
这也适用于更大的数字。复杂性是4 * n。