算法题解之 Item4box

将m个item分配到n个box中,每个box中可存多个item,每个item只能放到一个box中。试求所有可能的解。每个Box都是一样的,所以解没有顺序之分。也就是说2,3,5 和 2 ,5,3被认为是同样的解。

给出指定的m(m>=0)和n(n >0),请给出所有的解。

 

这个题可以按照分治递归的思路求解。当box 数量是1或者2时很容易求解。 当 box =1 时直接返回m就是所求解;当 box=2时,可以把m(例如m=5)分成两步进行求解,那么可能的组合为 (0<=i<=m/2, m-i)

(0 5)

(1 4)

(2 3)

当box >2时,可以把box按照box/2取中分解成两部分,同时按照上述分解m(Item数量)的方式将m进行分解。如此递归。

 

package com.tr.algorithm.example.item4box;

public class IntelliItemDist {
 
 public IntelliItemDist(){
  super();
 }
    /**
     * 递归分配item 到 box 中。
     * @param 待分发的item数量
     * @param 可用的box数量
     * @return 返回可用方案。
     */
   
 private int[][] dispatch(int item,int box){
  
  int[][] m = new int[0][0];
  if (box == 1){
   m = new int[1][1];
   m[0] = new int[]{item};
  }else if (box ==2){
   int middleItem = item/2;
   m = new int[middleItem+1][2];
   
   for (int i=0;i< m.length;i++){
    m[i] = new int[]{i,item-i};
   }
  }else if (box > 2){
   int middleBox = box/2; //取box中数,
   int middleItem = item/2;//取item中数
   for (int i =0 ; i <= middleItem;i++){
    int[][] left = dispatch(i,middleBox);
    int[][] right= dispatch(item-i,box-middleBox);
    int[][] lr = crossMerge(left,right);
    m = appendMerge(m,lr);

   }
  }
  
  return m;
 }
 /**
  * 将两个二维数组left[m][n],right[j][k]合并成m[m*j][]数组。
  */
 private int[][] crossMerge(int[][] left,int[][] right){
  int[][] m = new int[left.length * right.length][];
  int row = 0;
  for (int i=0;i< left.length;i++){
   for (int j=0;j< right.length;j++){
    int[] l = left[i];
    int[] r = right[j];
    m[row] = merge(l,r);
    row++;
   }
  }
  
  return m;
  
  
 }
 /**
  * 将两个二维数组left[m][n],right[j][k]合并成m[m+j][]数组。
  */
 private int[][] appendMerge(int[][] left,int[][] right){
  int[][] m = new int[left.length + right.length][];
  for (int i=0;i< left.length;i++){
        m[i] = left[i];
  }
  for (int i=left.length;i< m.length;i++){
       m[i] = right[i - left.length];
  }
  
  return m;
  
  
 }
 /**
  * 将两个一维数组left[m],right[j]合并成m[m+j]数组。
  */
 private int[] merge(int[] left,int[] right){
  int[] m = new int[left.length + right.length];
  System.arraycopy(left,0,m,0,left.length);
  System.arraycopy(right, 0, m, left.length, right.length);
  return m;
 }
 
 public static void main (String[] args){
  
            int item = 5,box=4;
      IntelliItemDist bpu = new IntelliItemDist();
      int[][] solution = bpu.dispatch(item,box);
     
      for (int i = 0;i<solution.length;i++){
       for (int j = 0;j<solution[i].length;j++){
        System.out.print(solution[i][j] + " ");
       }
       System.out.println();
      }
     
 }

}

方案输出如下:

0 0 0 5
0 0 1 4
0 0 2 3
0 1 0 4
0 1 1 3
0 1 2 2
0 2 0 3
0 2 1 2
1 1 0 3
1 1 1 2

 

目前改方法存在重复解决方案,原因是子问题不能互相独立。有时间再解。也请高手不吝赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值