题目链接 洛谷2404
【问题描述】自然数的拆分:任何一个大于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
注意,本题中N拆分出来的数x的范围是1<=x<N。假如x可以等于N,那么本题和整数划分是一个道理。现在,这里与整数划分这个题的答案只少1,即N拆分成N本身的情况。
整数划分可以参考:
http://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html
http://blog.csdn.net/sunquana/article/details/9245443
算法一 用回溯法来实现
针对所给问题,定义问题的解空间;如本题对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 }