N个小球放入M个盒子共有多少种方法,并输出的算法设计:
算法思路1 :暴力填充盒子
每个小球都可能放入M个盒子的任意一个,所以直接根据小球个数做递归即可,然后将存储放入hash中排重
//TODO
算法思路2 :递归填充盒子
即,每层递归仅考虑一个盒子放几个球,剩下的球交给下一个递归。
比如第一个盒子里放N个球,则剩下的都是0个;第一个盒子放n-1个球,问题就变成了1个球与M-1个盒子的问题...直到第一个盒子放0个球,问题变成了N个球与M个盒子的问题。
递归的入口是第1个盒子,那么递归的出口在哪?自然是最后一个盒子。当盒子只剩一个时候便不向下递归,还剩多少小球就全放进盒子里。
递归伪代码如下:
public void everyBox(int boxes , int balls ,String oneResult ){
if (boxes ==1){ //递归出口
thisResult = oneResult+balls
return
}
for( i=balls ; i >=0 ; i -- ){
thisResult = oneResult + (String) i
everyBox(boxes-1 , balls-i , thisResult) //递归
}
}
算法2优化:
上述递归只有一个出口,就是只剩一个box时候。不过这个程序还有一个可以优化的出口:在balls等于0的时候。假设还剩余X个盒子没有进行递归,而这时候剩余ball是0,便不用递归了,直接输出X个0即可。当盒子数>>小球数时候,可以极大减少递归的层次,提高代码效率。
优化后的java示例代码如下,由于要输出就直接systemout了:
public class NballMbox {
public static void main(String[] args) {
NballMbox nm = new NballMbox();
nm.iterator(4, 2, "");
}
public void iterator(int balls , int boxes , String s){
//ball =0 直接结算
if(balls == 0){
for(int i = 0 ;i< boxes ;i++)
s = s+ 0;
System.out.println(s.toString());
return;
}
for(int i =balls;i >=0;i--){
String s1 = s+i;
if(boxes == 1){
System.out.println(s1.toString());
return;
}
else
this.iterator(balls-i, boxes-1, s1);
}
}
}