【问题描述】自然数的拆分:任何一个大于1的自然数N,
总可以拆分成若干个自然数之和,并且有多种拆分方法。试求 n的所有拆分。
例如自然数5,可以有如下一些拆分方法:
5=1+1+1+1+1
5=1+1+1+2
5=1+2+2
5=1+4
5=2+3
算法一 用回溯法来实现
针对所给问题,定义问题的解空间;如本题对5的拆分来说,1<=拆分的数<=5。
确定用于搜索的解空间结构;如本题对5的拆分来说,用x[ ]数组来存储解,每个数组元素的取值范围都是1<=拆分的数<=5,从1开始搜索直到5。
搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
如本题对5的拆分来说,为了避免重复,x[i] >= x[j] ( i > j ),如x[]={2,3}满足条件而x[]={3,2}就不满足条件不是可行解即无效。
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 void splitN(int n,int m);// n是需要拆分的数,m是拆分的进度。 5 int x[1024]={0},total=0 ;// total用于计数拆分的方法数,x[]用于存储解 6 void main() 7 { 8 int n ; 9 printf("please input the natural number n:"); 10 scanf("%d",&n); 11 splitN(n,1); 12 printf("There are %d ways to split natural number %d. ",total,n); 13 } 14 15 void splitN(int n,int m) 16 {//n是需要拆分的数,m是拆分的进度 17 int rest,i,j; 18 for(i=1;i<=n;i++) 19 {//从1开始尝试拆分 20 if(i>=x[m-1]) 21 {//拆分的数大于或等于前一个从而保证不重复 22 x[m]=i ;// 将这个数计入结果中 23 rest=n-i ;// 剩下的数是n-i,如果已经没有剩下的了,并且进度(总的拆分个数)大于1,说明已经得到一个结果了 24 if(rest==0&&m>1) 25 { 26 total++; 27 printf("%d\t",total); 28 for(j=1;j<m;j++) 29 { 30 printf("%d+",x[j]); 31 } 32 printf("%d ",x[m]); 33 printf("\n"); 34 } 35 else 36 { 37 splitN(rest,m+1);// 否则将剩下的数进行进度为m+1拆分 38 } 39 x[m]=0;// 取消本次结果,进行下一次拆分。环境恢复,即回溯 40 } 41 } 42 }
算法二 用递归来实现
用不完全归纳法
n =2 可拆分成 2 =1 +1
n =3 可拆分成 3 =1 +2 =1 +1 +1
n =4 可拆分成 4 =1 +3 =1 +1 +2 =1 +1 +1 +1 =2 +2
……
n =7 可拆分成 7=1 +6
=1 +1 +5
=1 +1 +1 +4
=1 +1 +1 +1 +3
=1 +1 +1 +1 +1 +2
=1 +1 +1 +1 +1
=1 +1 +1 +2 +2
=1 +1 +2 +3
=1 +2 +4
=1 +2 +2 +2
=1 +3 +3
=2 +5
=2 +2 +3
=3 +4
用数组 a 存储完成 n 的一种拆分。从上面不完全归纳法的分析 n =7 时,
按 a[1]分类,有a[1]=1,a[1]= 2,…,a[1]= n/2,共 n/2 大类拆分。
在每一类拆分时,a[1]= i ,a[2]= n - i ,从 k=2,从 a[k]开始继续拆分,
a[k]能否再拆分取决于 a[k]/2 是否大于等于 a[k-1]。
递归过程的参数 t 指向要拆分的数 a[k]
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int a[100]={0}; 5 void Split(int t) 6 { 7 int i,j,L; 8 for(i = 1; i <t; i++) 9 { 10 printf("%d+",a[i]); 11 } 12 printf("%d\n",a[i]); 13 14 j = t; 15 L = a[j]; 16 for(i = a[j-1]; i <= L/2; i++) 17 { 18 a[j] = i; 19 a[j+1] = L - i; 20 Split(j+1); 21 } 22 } 23 24 void SplitNum(int n) 25 { 26 int i; 27 for(i = 1; i <= n/2; i++) 28 { 29 a[1] = i; 30 a[2] = n - i; 31 Split(2); 32 } 33 } 34 int main() 35 { 36 int n; 37 scanf("%d",&n); 38 SplitNum(n); 39 return 0; 40 }
参考:http://wenku.baidu.com/link?url=H7tDqvEmnds9SN4FfuwMw8M6AfAMUl44-vCR83Z4LKv9UN-HAU159GJtFR5M48t11XBJFMwP3i4qPk6u2WHEORZDeYhraBQt63zvaDUNSAi