目标:编写递归程序,求正整数的所有不同的划分组合。例如输入6,则输出:
6 = 5+1
6 = 4+2
6 = 4+1+1
6 = 3+3
6 = 3+2+1
6 = 3+1+1+1
6 = 2+2+2
6 = 2+2+1+1
6 = 2+1+1+1+1
6 = 1+1+1+1+1+1
解决方法
从特殊到一般,观察上面6的划分,发现6=5+1;6=4+2;6=3+3;6=2+4;6=1+5;之后在对1(5之后)、2(4之后)、3(3之后)、4(2之后)、5(1之后)进行整数划分,为确保不重不漏,这里划分后的每个数小于等于原来划分首数,如最后5的划分后的数(1、1、1、1、1)均小于等于划分首数1,即
n=n-k+k(k=1、2、……、n-1)然后对k进行划分,划分分后每个数均不大于n-k;划分中含划分,A函数调用A函数,这里不难想到采用递归的做法,
问题归约于1.建立递归子式2.寻找递归出口
这里十分突兀地引入整数划分公式,对整数n进行划分,且划分后的每个数最大值小于等于整数m,划分的方法数记为f(n,m)
1. n=1 f(1,m)=1;
2. m=1 f(n,1)=f(n-1,1)=……=f(1,1)=1;
3. n>m f(n,m)=f(n-m,m)+f(n,m-1) //这里对m的划分看成两部分,第一部分中划分后存在至少一个值为最大值为m, 第二部分划分后每个值均小于m,即可看成对m-1的划分,类比组合数公式:C(M,N) = C(M-1,N-1)+C(M-1,N)
4. n=m f(n,m)=f(n,n-1)
5. n<m f(n,m)=f(n,n) //这里不直接一步到位到f(n,n-1)为了输出当m=n时的整数划分,而非将m=n直接进入m=n-1
引入整数划分公式 ,递归出口、递归子式都确立,最后建立数组保存划分数即可
#include<stdio.h>
static int n1;
void divide(int n,int m,int *a,int i);
void print(int *a,int i);
int main()
{
int n,i,a[100];
while(scanf("%d",&n))
{
n1=n;
divide(n,n-1,a,0);
}
return 0;
}
void divide(int n,int m,int *a,int i)
{
if(n==1) {a[i]=1;print(a,i);return;}
else if(m==1){a[i]=1;i++;divide(n-1,m,a,i);}
else if(m<n){a[i]=m;i++;divide(n-m,m,a,i);divide(n,m-1,a,i-1);}
else if(m==n){a[i]=m;print(a,i);divide(n,n-1,a,i);}
else if(m>n){divide(n,n,a,i);}
}
void print(int *a,int i)
{
printf("%d=%d",n1,a[0]);
for(int j=1;j<=i;j++)
{
printf("+%d",a[j]);
}
printf("\n");
}