整数的拆分

1.问题提出

   整数s的拆分是把s分成为某些指定正整数之和,拆分式中不允许零数重复,且不记零数的次序。试求s共有多少个不同的拆分式?展示出s的所有这些拆分式。

2.递归设计

   注意到拆分与式中各零数的排列顺序无关,我们考虑从1~m这m个数中取k(k<m)个数的所有组合结果入手:设comb(int m, int k)为从1~m这m个数中取k个数的所有组合结果。

   当组合的第一个数字选定时,其后的数字是从余下的m-1个数中取k-1个数的组合。这就把从m个数中取k个数的组合问题转化为从m-1个数中取k-1数的组合问题。

   设置数组a[]存放救出的组合数字,约定函数将确定的k个数字组合的第一个数字放在a[k]中,当一个组合求出后,才将a[]的一个组合输出。第一个数可以是m, m-1, ..., k,函数将确定组合的第一个数字放入数组后,有两种选择:还未确定组合的其余元素时,继续递归确定组合的其余元素;已确定组合的全部元素时,输出这个组合。

   对于给定的和数s与最大零数m,首先计算拆分式中零数的最少个数wmin与零数的最多个数wmax,显然,拆分式中零数的个数k取在区间[wmin,wmax]中。

   建立三参数m、k、s的递归函数comb(m,k,s),当选取的第一个数i选定时,其后的数字是从余下的i-1个数中取k-1个数的组合。对所选取的k个数,求其和t并与和数s进行比较:若t=s,即找到一个拆分式,进行打印输出,并设置变量n统计拆分式的个数。

 

3.代码

 // 整数的拆分 #include <stdio.h> #define MAXN 100 // 数组a[]存放求出的组合数字 // n统计拆分的种数 int a[MAXN], t, n = 0; void comb(int m, int k, int s) { int i, j; for (i = m; i >= k; i--) { a[k] = i; if (k == 1) { for (t = 0, j = a[0]; j > 0; j--) t += a[j]; if (t == s) { n++; printf("%d=", s); // 满足条件时输出 for (j = a[0]; j > 1; j--) printf("%2d+", a[j]); printf("%2d/n", a[1]); } } else comb(i - 1, k - 1, s); } } int main(void) { int ms, ss, i, h, k, wmin, wmax; printf("请输入和数,最大零数:"); scanf("%d%d", &ss, &ms); for (h = 0, i = 1; i <= ms; i++) { h += i; if (h > ss) { wmax = i - 1; break; } } // 输入的最大零数太小,程序返回 if (i > ms) { printf("输入的最大零数太小!/n"); return 0; } for (h = 0, i = 1; i <= ms; i++) { h += ms - i + 1; if (h > ss) { wmin = i - 1; break; } } for (k = wmin; k <= wmax; k++) { a[0] = k; comb(ms, k, ss); } // 输出拆分种数 printf("n = %d/n", n); return 0; }

 

二、可以重复的所有情况

 

1.递推计算分划种数

⑴递推关系的确定

   设n的“最大零数不超过m” 的分划式个数为q(n, m),这里m<=n,则

                  q(n,n)=1+q(n, n-1)

   等式右边的“1”表示n等于n本身;q(n,n-1)表示n的所有其他分划,即最大零数不超过n-1的分划。

                  q(n,m)=q(n,m-1)+q(n-m,m)  (1<m<n)

    其中q(n,m-1)表示零数中不包含m的分划式数目;q(n-m,m)表示零数中包含m的分划数目,因为如果确定了一个分划的零数中包含m,则剩下的部分就是对于n-m进行不超过m的分划。

    注意:如果n-m<m时,取q(n-m,m)=q(n-m,n-m),初始条件:q(n,0)=0, q(1,m)=1

2.程序实现

// 整数分划递推计数 #include <stdio.h> #include <math.h> int main() { int s, m, n; long q[121][121]; printf("请输入整数s:"); // 输入分划的整数 scanf("%d", &s); for (m = 1; m <= s; m++) { // 确定初始条件 q[m][0] = 0; q[1][m] = 1; } for (n = 2; n <= s; n++) { for (m = 1; m <= n -1; m++) { if (n - m < m) q[n - m][m] = q[n -m][n - m]; q[n][m] = q[n][m - 1] + q[n - m][m]; // 实施递推 } q[n][n] = q[n][n - 1] + 1; // 加上n=n这一个分划式 } printf("整数%d的分划种数:%ld/n", s, q[s][s]); return 0; }

 

你可能感兴趣的:(整数的拆分)