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]); } }
小于等于n的正整数相加等于m的一个算法
最新推荐文章于 2021-04-06 12:23:25 发布