package suanfa;
public class Suanfa {
/**
* 对任意的自然数n,m,取任意多个小于等于n的自然数相加,结果等于m,求所有的这种组合。
* 如n=3,m=5可以有:1,1,3;1,2,2;2,3;5等
* 算法:
* 可将此问题看做是将m个圆环往n跟柱子上套,不分先后次序,求所有套法的问题。
* 主要思想是:
* 将所有的组合分类为,
* 第1类:k=0,即至少有一根柱子上套了0个环,其他n-1个柱子上套m个环;
* 第2类:k=1,即至少有一根柱子上的环数为1,其他n-1个柱子上套m-1个环,并且这n-1根柱子的每根柱子套的环数必须大于或等于k=1,
* 即大于等于1;因为在第1类里的所有组合中必定有一个柱子上的环数为0,而此类中的所有组合中每根柱子上的环数都必须大于等于1,
* 所以此类和第1类没有重复的组合;
* 第3类:k=2,即至少有一根柱子上的环数等于2,且每根柱子上的环数不小于2,因为第2类中至少有一根柱子上环数为1,所以此类和
* 第2类中的组合没有重复,同理和第1类中的组合也没有重复;
* 。。。
* 第r类:k=r-1,即至少有一根柱子上的环数等于r-1,且每根柱子上的环数不小于r-1,此类和前面的所有类中的组合都不重复
* 如上述分法,假设任意一种满足题意的组合,此组合必定属于上面的第i类组合,i为此组合中最小的元素。如果此组合的元素
* 个数小于n,则不足的补0,即最小的元素必定为0,即此组合必定属于第1类组合。
* 下面确定总共有多少个类:r = [m/n] + 1,[m/n]为向下取整.
* 因为总环数为m,假设按以上方法可以分为k类,则第k类里的环数 M = m1+m2+...+mn,因为mi(i属于1...n)>=k,所以n*k<=M<=m;即k<=m/n
* 主要实现步骤:
* 先按k循环,然后递归找出每一类中的所有组合。
* @param n 用于相加的数可以取值的最大值。
* @param m 目标数,相加后的目标结果数。
* @param k 拥有限制求和表达式里的元素的,即调用该方法所生成的表达式里的元素都必须大于或等于k,且有一个元素必须等于k。
* 第一次调用时为0,即生成的表达式里必须有一个元素为0,且所有元素都必须大于0.
* @param door 元素取值的限定数。用于限定元素取值的最大数。主要用处是:当n<m的时候,所有表达式里的元素值都应小于n,而不是m,
* 因为递归调用的时候,此函数的第一个参数是变化的,所以不能用第一个参数来限定。
* @param a 用于存储一种组合。a[i]代表第i根柱子上的环数。
*/
public static void func1_2(int n, int m, int k, int door, int[] a){
//当n>m时,所有大于m的数是用不到的
if(n>m) n = m;
//当m=1时,只有一种组合,就是一根柱子上环数为1,其他柱子上环数为0
if(m==1&&m>=k){
a[a.length-n]=1;
printA(a);
return;
}else if(n==1){ //n=1的时候只有一种组合,就是这根柱子上的环数为m
if(m<=door){ //door的值就是n,如果m>n,则组合中不能出现比n大的数
a[a.length-n]=m;
printA(a);
}
return;
}else {
int i = 0;
while(n*i<=m){ //按上面的分类方法循环
if(i>=k){ //每根柱子上的环数必须大于k
if(i>0) //因为a[i]默认为0
/* 当递归到第n层时,表明前面的0到a.length-n-1根柱子上的环数已经确定。
* 此处就是确定第a.length-n跟元素上的环数
*/
a[a.length-n]=i;
/*递归调用此函数,因为上面确定了一根柱子上的环数,所以未确定的柱子数为n-1,因为上面确定的柱子上的环数为i,
* 所以此处待确定的环数为m-i;此处的n,m为递归调用时传入的n,m和初始的n,m可能不一样
*/
func1_2(n-1,m-i,i,door,a);
}
//类别自增
i++;
}
}
}
//输出一个组合
public static void printA(int[] a){
for(int i = 0; i < a.length; i++){
if(a[i]>0&&i!=a.length-1){
System.out.print(a[i]+"+");
}else if(a[i]>0){
System.out.print(a[i]);
}
}
System.out.println();
}
public static void main(String[] args) {
//func1_1(6,6,0,6);
func1_2(3,6,0,3,new int[3]);
}
}