整数分界(递归)

    xiaoxiao2021-03-25  86

    来源: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   #include <iostream>   using namespace std;      #define MAX 20      int res_num;   // 因子暂存在res数组中   int res[MAX];   int p_res = 0;      // 将n进行分解   void resolve(int n);      int main() {       while (1) {           int n;           cin >> n;           resolve(n);           cout << "total num of res:\t" << res_num << endl;           res_num = 0;       }       return 0;   }      void resolve(int n) {       if (n<=0) { // 出口           for (int i=0; i<p_res; i++)               cout << res[i] << " ";           cout << endl;           res_num++;       }          for (int i=1; i<=n; i++) {           res[p_res] = i;           p_res++;        // p_res++来顺次存储各个因子           resolve(n-i);           p_res--;        // 此行必须有,执行完上一行,下一次for循环即使第一个因子       }   }   可以发现上述代码输出的结果有重复答案,如当n=4时,会输出1 3,和3 1两组解,其实他们是相同的。

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

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

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

    [cpp]  view plain  copy   #include <iostream>   using namespace std;      #define MAX 20      int res_num;   // 因子暂存在res数组中   int res[MAX];   int p_res = 0;      // 将n进行分解   void resolve(int n, int min_factor=1);      int main() {       while (1) {           int n;           cin >> n;           resolve(n);           cout << "total num of res:\t" << res_num << endl;           res_num = 0;       }       return 0;   }      void resolve(int n, int min_factor) {       if (n<=0) { // 出口           for (int i=0; i<p_res; i++)               cout << res[i] << " ";           cout << endl;           res_num++;       }          for (int i=min_factor; i<=n; i++) {     // 此处修改           res[p_res] = i;           p_res++;        // p_res++来顺次存储各个因子           resolve(n-i, i);<span style="white-space:pre">      </span>// 此处修改           p_res--;        // 此行必须有,执行完上一行,下一次for循环即使第一个因子       }   }  

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

    定义函数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   #include <iostream>   using namespace std;      #define MAX 200      int dp[MAX][MAX];      // 将n进行分解   int resolve(int n, int min_factor=1);      int main() {       while (1) {           int n;           cin >> n;           cout << "total num of res:\t" << resolve(n) << endl;       }       return 0;   }      int resolve(int n, int min_factor) {       if (min_factor > n)           return 0;       if (dp[n][min_factor]!=0)           return dp[n][min_factor];       if (n == min_factor) {           dp[n][min_factor] = 1;           return 1;       }       return dp[n][min_factor] = resolve(n, min_factor+1) + resolve(n-min_factor, min_factor);   }   同样也可以用此种方法来打印结果(不过不能使用动态规划了,因为动态规划省略了一些重复的求解过程,这些过程也会产生出结果),代码如下:

    [cpp]  view plain  copy   #include <iostream>   using namespace std;      #define MAX 20      // 因子暂存在res数组中   int res[20];   int p_res = 0;      // 将n进行分解   int resolve(int n, int min_factor=1);      int main() {       while (1) {           int n;           cin >> n;           cout << "total num of res:\t" << resolve(n) << endl;       }       return 0;   }      int resolve(int n, int min_factor) {       if (min_factor > n)           return 0;       if (min_factor == n) {           res[p_res] = min_factor;           p_res++;           for (int i=0; i<p_res; i++)               cout << res[i] << " ";           cout << endl;           p_res--;           return 1;       }       res[p_res] = min_factor;       p_res++;       int k = resolve(n-min_factor, min_factor);       p_res--;          int s = resolve(n, min_factor+1);       return k+s;   }   进一步,如果要求分解后的因子也要不同,怎么办呢?

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

    [cpp]  view plain  copy   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)

    代码就不写了

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

    转载请注明原文地址: https://ju.6miu.com/read-34668.html

    最新回复(0)