整数分界(递归)

来源:http://blog.csdn.net/u012492780/article/details/21558005


题目大意:给定一个整数n,找到k个数,使得其和等于n。

解题思路:要分解整数n,肯定先要找到一个因子,然后我们会发现,剩下的问题还是一个整数分解问题,因此容易得到问题的解。
定义函数f(n)为n可以分解的解的个数,即可以先分解出一个数字k(k = 0,1,2,……,n),然后再分解f(k),可以得出有:
          f(n) = f(n-1) + f(n-2) + ……+ f(1) + f(0),其中f(0) = 1
于是可以解得f(n) = 2^(n-1) ,n>=1

下面附代码将每组解打印出来,并验证上述式子,代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define MAX 20  
  5.   
  6. int res_num;  
  7. // 因子暂存在res数组中  
  8. int res[MAX];  
  9. int p_res = 0;  
  10.   
  11. // 将n进行分解  
  12. void resolve(int n);  
  13.   
  14. int main() {  
  15.     while (1) {  
  16.         int n;  
  17.         cin >> n;  
  18.         resolve(n);  
  19.         cout << "total num of res:\t" << res_num << endl;  
  20.         res_num = 0;  
  21.     }  
  22.     return 0;  
  23. }  
  24.   
  25. void resolve(int n) {  
  26.     if (n<=0) { // 出口  
  27.         for (int i=0; i<p_res; i++)  
  28.             cout << res[i] << " ";  
  29.         cout << endl;  
  30.         res_num++;  
  31.     }  
  32.   
  33.     for (int i=1; i<=n; i++) {  
  34.         res[p_res] = i;  
  35.         p_res++;        // p_res++来顺次存储各个因子  
  36.         resolve(n-i);  
  37.         p_res--;        // 此行必须有,执行完上一行,下一次for循环即使第一个因子  
  38.     }  
  39. }  

可以发现上述代码输出的结果有重复答案,如当n=4时,会输出1 3,和3 1两组解,其实他们是相同的。

如果要求答案不能重复呢?

同样,我们可以定义一个函数f(n, min_factor),其中min_factor表示n分解后因子中的最小值,这样即可通过min_factor来限制for循环的初始值,达到因子从小到大输出的目的,从而避免相同的解重复输出

稍微修改上述代码,即可得到解,同样贴出代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define MAX 20  
  5.   
  6. int res_num;  
  7. // 因子暂存在res数组中  
  8. int res[MAX];  
  9. int p_res = 0;  
  10.   
  11. // 将n进行分解  
  12. void resolve(int n, int min_factor=1);  
  13.   
  14. int main() {  
  15.     while (1) {  
  16.         int n;  
  17.         cin >> n;  
  18.         resolve(n);  
  19.         cout << "total num of res:\t" << res_num << endl;  
  20.         res_num = 0;  
  21.     }  
  22.     return 0;  
  23. }  
  24.   
  25. void resolve(int n, int min_factor) {  
  26.     if (n<=0) { // 出口  
  27.         for (int i=0; i<p_res; i++)  
  28.             cout << res[i] << " ";  
  29.         cout << endl;  
  30.         res_num++;  
  31.     }  
  32.   
  33.     for (int i=min_factor; i<=n; i++) {     // 此处修改  
  34.         res[p_res] = i;  
  35.         p_res++;        // p_res++来顺次存储各个因子  
  36.         resolve(n-i, i);<span style="white-space:pre">      </span>// 此处修改  
  37.         p_res--;        // 此行必须有,执行完上一行,下一次for循环即使第一个因子  
  38.     }  
  39. }  

其实,如果只要求出分解的解的个数,可以按照如下方法:

定义函数f(n, m),其中m表示n分解后因子中的最小值,则有

当(n<m)时,即最小因子大于n,则返回0,f(n,m)  =  0 

当(n==m,即最小因子等于自身),  f(n,m) = 1 

其他情况,f(n,m) = f(n,m+1) + f(n-m, m)       (即分解的结果可以分为两类,1. 分解后的因子中不包含m,即f(n,m+1);2. 分解后的因子中包含,即f(n-m, m),两种情况的结果相加就是结果了)

易知,动态规划可以加速求解,附代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define MAX 200  
  5.   
  6. int dp[MAX][MAX];  
  7.   
  8. // 将n进行分解  
  9. int resolve(int n, int min_factor=1);  
  10.   
  11. int main() {  
  12.     while (1) {  
  13.         int n;  
  14.         cin >> n;  
  15.         cout << "total num of res:\t" << resolve(n) << endl;  
  16.     }  
  17.     return 0;  
  18. }  
  19.   
  20. int resolve(int n, int min_factor) {  
  21.     if (min_factor > n)  
  22.         return 0;  
  23.     if (dp[n][min_factor]!=0)  
  24.         return dp[n][min_factor];  
  25.     if (n == min_factor) {  
  26.         dp[n][min_factor] = 1;  
  27.         return 1;  
  28.     }  
  29.     return dp[n][min_factor] = resolve(n, min_factor+1) + resolve(n-min_factor, min_factor);  
  30. }  

同样也可以用此种方法来打印结果(不过不能使用动态规划了,因为动态规划省略了一些重复的求解过程,这些过程也会产生出结果),代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define MAX 20  
  5.   
  6. // 因子暂存在res数组中  
  7. int res[20];  
  8. int p_res = 0;  
  9.   
  10. // 将n进行分解  
  11. int resolve(int n, int min_factor=1);  
  12.   
  13. int main() {  
  14.     while (1) {  
  15.         int n;  
  16.         cin >> n;  
  17.         cout << "total num of res:\t" << resolve(n) << endl;  
  18.     }  
  19.     return 0;  
  20. }  
  21.   
  22. int resolve(int n, int min_factor) {  
  23.     if (min_factor > n)  
  24.         return 0;  
  25.     if (min_factor == n) {  
  26.         res[p_res] = min_factor;  
  27.         p_res++;  
  28.         for (int i=0; i<p_res; i++)  
  29.             cout << res[i] << " ";  
  30.         cout << endl;  
  31.         p_res--;  
  32.         return 1;  
  33.     }  
  34.     res[p_res] = min_factor;  
  35.     p_res++;  
  36.     int k = resolve(n-min_factor, min_factor);  
  37.     p_res--;  
  38.   
  39.     int s = resolve(n, min_factor+1);  
  40.     return k+s;  
  41. }  

进一步,如果要求分解后的因子也要不同,怎么办呢?

min_factor不是控制因子的最小值么,将for中对resolve函数的调用改为如下行即可:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. resolve(n-i, i+1);  
这样n分解的因子就各不相同了

也可以定义f(n, max_factor)来求解,max_factor 为最大因子,其递推公司如下:

当(n<=1 || m==1)时,f(n, max_factor) = 

当(max_factor > n)时, f(n, max_factor) = f(n, n) 

其他情况,f(n, max_factor) =  f(n-max_factor, max_factor) + f(n, max_factor-1)

代码就不写了

最后,建议对待递归的出口慎重(我在此犯了小错误),仔细读一下,然后最好动手写一下,毕竟眼过千遍,不如手过一遍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值