Java 在n个箱子中分配物品的i号,其中每个箱子具有不同的容量等级c1、c2

Java 在n个箱子中分配物品的i号,其中每个箱子具有不同的容量等级c1、c2,java,algorithm,Java,Algorithm,我必须分发我的文件。n个箱子中的物品数量,每个箱子具有不同的容量等级c1、c2。。。中国。我想按容量的比例分配物品。因此,容量最高的盒子将包含最多的物品,反之亦然。容量可能不是按升序排列的。容量也可以是0。此外,如果项目数量超过总容量,则将所有箱子装满,直至其最大容量 这个问题已经有解决办法了吗 因为我写了下面的算法。但它的效率不高。同时,它在以下输入处无限循环。因为-2的差异从未解决过。因此,在其他用例中,它也会出现故障 int[] arrCap = {1,1,0,1,1}; new Dist

我必须分发我的文件。n个箱子中的物品数量,每个箱子具有不同的容量等级c1、c2。。。中国。我想按容量的比例分配物品。因此,容量最高的盒子将包含最多的物品,反之亦然。容量可能不是按升序排列的。容量也可以是0。此外,如果项目数量超过总容量,则将所有箱子装满,直至其最大容量

这个问题已经有解决办法了吗

因为我写了下面的算法。但它的效率不高。同时,它在以下输入处无限循环。因为-2的差异从未解决过。因此,在其他用例中,它也会出现故障

int[] arrCap = {1,1,0,1,1};
new Distributor(arrCap, 2).distribute();



import java.util.Arrays;
public class Distributor {

    /** Capacity of each box */
    private final int[] boxCapacity;
    /** Total no. of boxes */
    private final int NO_OF_BOXES;
    /** Total no. of items that are to be distributed into each box  */
    private final int NO_OF_ITEMS;
    /** Total capacity available. */
    private long totalCapacity;
    /** Fractionally ratio distributed items according to capacity */
    private float[] fractionalRatios;
    /** Ratio distributed items according to capacity */
    private int[] ratioDistributedCapacity;
    /** Sorted Rank of distributed items in ascending / descending order */
    private int[] rankIndex;
    /** The difference between the totalCapacity and total of ratioDistributedCapacity */
    private int difference;

    /**
     * Validates the total capacity and no. of items to be distributed.
     * Initializes the distributor with box capacity array, no of items.
     * Implicitly calculates no. of boxes as length of box capacity array.
     * @param boxCapacity Array of capacity of each box.
     * @param noOfItems No. of Items to be distributed.
     */
    public Distributor(int[] boxCapacity, int noOfItems) {
        calculateBoxes(boxCapacity);
        this.boxCapacity = boxCapacity;
        this.NO_OF_ITEMS = noOfItems;
        NO_OF_BOXES = boxCapacity.length;
        ratioDistributedCapacity = new int[NO_OF_BOXES];
        rankIndex = new int[NO_OF_BOXES];
    }

    /**
     * Calculates the ratio into which the items are to be distributed.
     * Actually assigns the items into each box according to the ratio.
     * @return Array of int[] containing ratio distributed items according to its capacity.
     */
    public int[] distribute() {
        // If NO_OF_ITEMS to be distributed is more than totalCapacity then distribute all the items upto full capacity
        if (NO_OF_ITEMS >= totalCapacity) {
            ratioDistributedCapacity = boxCapacity;
        } else {
            calculateRatioAndDistribute();
        }
        return ratioDistributedCapacity;
    }

    /**
     * Calculates the ratio & distributes the items according to the capacity.
     */
    private void calculateRatioAndDistribute() {
        fractionalRatios = new float[NO_OF_BOXES];
        for (int i=0; i<NO_OF_BOXES; i++) {
            fractionalRatios[i] = ((float) boxCapacity[i] * (float) NO_OF_ITEMS) / (float) totalCapacity;
            ratioDistributedCapacity[i] = Math.round(fractionalRatios[i]);
        }
        print(fractionalRatios);
        print(ratioDistributedCapacity);
        // keep redistributing the difference until its not 0
        while ((difference = rectifyAndGetDistributionResult()) != 0) {
            redistribute();
        }
        print(ratioDistributedCapacity);
    }

    /**
     * Redistributes the difference between the already allotted ratioDistributedCapacity array.
     * Also if the difference is 0 that means everything is already settled.
     * No more further need to do anything.
     * @param difference the difference that needs to be settled to equal the no. of items with total distributed items.
     */
    private void redistribute() {
        if (difference > 0) {
            // calculate distribution ranks in ascending order
            calculateDistributionRanks(true);   // orderDescending = true
            // eliminate the invalid ranks from rankIndex
            eliminateInvalidRanks();
            // In case all the ranks have become invalid. In this case the rankIndex will be empty.
            // So we need to re calculate the distribution ranks in opposite order.
            if (rankIndex.length == 0) {
                calculateDistributionRanks(false);  // orderDescending = false
            }
        } else if (difference < 0) {
            // calculate distribution ranks in descending order
            calculateDistributionRanks(false);  // orderDescending = false
            // eliminate the invalid ranks from rankIndex
            eliminateInvalidRanks();
            // In case all the ranks have become invalid. In this case the rankIndex will be empty.
            // So we need to re calculate the distribution ranks in opposite order.
            if (rankIndex.length == 0) {
                calculateDistributionRanks(true);   // orderDescending = true
            }
        }
        // add / substract 1 from the ratioDistributedCapacity of the element in order of the rankIndex
        // according to negative / positive difference until the difference becomes 0.
        final int len = rankIndex.length;
        for (int i=0; i<len; i++) {
            if (difference == 0) {
                break;
            } else if (difference > 0) {
                ratioDistributedCapacity[ rankIndex[i] ]++;
                difference--;
            } else if (difference < 0) {
                ratioDistributedCapacity[ rankIndex[i] ]--;
                difference++;
            }
        }
    }

    /**
     * If the value of any ratioDistributedCapacity element exceeds its capacity or is less than 0,
     * revert it with its initial capacity value.
     */
    private void rectify() {
        for (int i=0; i<NO_OF_BOXES; i++) {
            ratioDistributedCapacity[i] = ((ratioDistributedCapacity[i] > boxCapacity[i]) || (ratioDistributedCapacity[i] < 0)) ? boxCapacity[i] : ratioDistributedCapacity[i];
        }
    }

    /**
     * Calculates the distribution ranks i.e. indexes of fractionalRatios array.
     * Sorts them into ascending or descending order.
     * @param orderDesc Sort order. true for descending and false for ascending.
     */
    private void calculateDistributionRanks(boolean orderDesc) {
        // Copy fractionalRatios array to another tmp array. Note:- Use fractionalRatios so ranking can be more accurate.
        float[] tmp = Arrays.copyOf(fractionalRatios, NO_OF_BOXES);
        // Sort the array in ascending order
        Arrays.sort(tmp);
        // re-initialize the rankIndex array
        rankIndex = new int[NO_OF_BOXES];
        for (int i=0; i<NO_OF_BOXES; i++) {
            innerLoop: for (int j=0; j<NO_OF_BOXES; j++) {
                if (tmp[i] == fractionalRatios[j]) {
                    // Store the array index of unsorted array if its value matches value of sorted array.
                    rankIndex[i] = j;
                    break innerLoop;
                }
            }
        }
        // reverse the rank array if orderDesc flag is true
        if (orderDesc) reverse();
        print(rankIndex);
    }

    /**
     * Remove the indexes from rank which are already full or equal to 0
     * or are not eligible for increment / decrement operation.
     */
    private void eliminateInvalidRanks() {
        final int len = rankIndex.length;
        int invalidRankCount = 0;
        final int markInvalidRank = -1;
        for (int i = 0; i < len; i++) {
            if (boxCapacity[rankIndex[i]] <= 0) {
                // mark this rank number as invalid, for removal
                rankIndex[i] = markInvalidRank;
                invalidRankCount++;
                continue;
            }
            if (difference > 0) {
                if ((ratioDistributedCapacity[rankIndex[i]] >= boxCapacity[rankIndex[i]])) {
                    // mark this rank number as invalid, for removal
                    rankIndex[i] = markInvalidRank;
                    invalidRankCount++;
                    continue;
                }
            } else if (difference < 0) {
                if (ratioDistributedCapacity[rankIndex[i]] <= 0) {
                    // mark this rank number as invalid, for removal
                    rankIndex[i] = markInvalidRank;
                    invalidRankCount++;
                    continue;
                }
            }
        }
        int[] tmp = new int[(len - invalidRankCount)];
        int j = 0;
        for (int i = 0; i < len; i++) {
            if (rankIndex[i] != markInvalidRank) {
                tmp[j++] = rankIndex[i];
            }
        }
        rankIndex = tmp;
        print(rankIndex);
    }

    /**
     * Rectifies the elements value inside ratioDistributedCapacity.
     * Calculates the total of already distributed items.
     * @return Difference between total distributed items and initial no. of items that were to be distributed.
     */
    private int rectifyAndGetDistributionResult() {
        rectify();
        int remaining = NO_OF_ITEMS;
        for (int tmp: ratioDistributedCapacity) {
            remaining -= tmp;
        }
        return remaining;
    }

    /**
     * Validates the capacity array and no. of items to be distributed.
     * @param arrCapacity Array of capacity of each box.
     */
    private void calculateBoxes(int[] arrCapacity) {
        for (int i: arrCapacity) {
            totalCapacity += i;
        }
    }

    /**
     * Prints the array elements and the total of the elements within it.
     * @param x
     */
    private void print(int[] x) {
        final int len = x.length;
        final StringBuilder sb = new StringBuilder("");
        for (int i=0; i<len; i++) {
            sb.append(x[i]).append(", ");
        }
        System.out.println(sb.toString());
    }

    /**
     * Prints the array elements and the total of the elements within it.
     * @param x
     */
    private void print(float[] x) {
        final int len = x.length;
        final StringBuilder sb = new StringBuilder("");
        for (int i=0; i<len; i++) {
            sb.append(x[i]).append(", ");
        }
        System.out.println(sb.toString());
    }

    private void reverse() {
        final int len = rankIndex.length;
        for (int i=0; i < (len/2); i++) {
            rankIndex[i] += rankIndex[len - 1 - i]; //  a = a+b
            rankIndex[len - 1 - i] = rankIndex[i] - rankIndex[len - 1 - i]; //  b = a-b
            rankIndex[i] -= rankIndex[len - 1 - i]; //  a = a-b
        }
    }
}
int[]arrCap={1,1,0,1,1};
新分配器(arrCap,2)。distribute();
导入java.util.array;
公共类分发服务器{
/**每个箱子的容量*/
私人最终通行能力;
/**箱子总数*/
专用最终整备箱编号;
/**要分发到每个箱子中的项目总数*/
项目的专用最终整数编号;
/**总可用容量*/
私人长期总容量;
/**根据容量对分配的项目进行分数比率*/
私人浮动利率;
/**按容量分配的项目比率*/
私人int[]比例分配容量;
/**按升序/降序排列的已分发项目的排序*/
私人内特[]兰金德克斯;
/**总容量与比率分配容量之差*/
私人智力差异;
/**
*验证要分发的项目的总容量和数量。
*使用盒子容量数组初始化分发服务器,项目数为。
*隐式计算盒子数量作为盒子容量数组的长度。
*@param-boxCapacity每个盒子的容量数组。
*@param noOfItems要分发的项目数。
*/
公共分销商(国际[]箱容量,国际noOfItems){
计算箱(箱容量);
this.boxCapacity=boxCapacity;
此项的数量=不适用项;
箱的数量=箱容量.length;
ratioDistributedCapacity=新的整数[NO_OF_Box];
rankIndex=新整数[框的数量];
}
/**
*计算项目要分配到的比率。
*根据比率将项目实际分配到每个框中。
*@return int[]数组,包含按容量分配的比率项。
*/
公共int[]分发(){
//如果要分配的项目中没有超过总容量的项目,则将所有项目分配到最大容量
if(无项目>=总容量){
比率分配容量=箱容量;
}否则{
计算和分配();
}
收益率分布容量;
}
/**
*计算比率并根据容量分配项目。
*/
私有void calculateRatioAndDistribute(){
分馏率=新浮点数[无浮点数];
对于(int i=0;i 0){
//按升序计算分布等级
calculateDistributionRanks(true);//orderDescending=true
//从rankIndex中删除无效列组
消除不合格品();
//如果所有等级都无效,则rankIndex将为空。
//因此,我们需要按相反的顺序重新计算分布等级。
如果(rankIndex.length==0){
calculateDistributionRanks(false);//orderDescending=false
}
}否则如果(差异<0){
//按降序计算分发级别
calculateDistributionRanks(false);//orderDescending=false
//从rankIndex中删除无效列组
消除不合格品();
//如果所有等级都无效,则rankIndex将为空。
//因此,我们需要按相反的顺序重新计算分布等级。
如果(rankIndex.length==0){
calculateDistributionRanks(true);//orderDescending=true
}
}
//按照rankIndex的顺序,从元素的ratioDistributedCapacity中添加/减去1
//根据负/正差值,直到差值变为0。
最终整数长度=rankIndex.长度;
对于(int i=0;i 0){
比率分配容量[rankIndex[i]]++;
差异--;
}否则如果(差异<0){
比率分配容量[rankIndex[i]]-;
差异++;
}
}
}
/**
*如果任何ratioDistributedCapacity元素的值超过其容量或小于0,
*将其还原为初始容量值。
*/
私人机构{
对于(int i=0;i boxCapacity[i])| |(ratioDistributedCapacity[i]<0))?boxCapacity[i]:ratioDistributedCapacity[i];
}
}
/**
*计算分布等级,即分数比率数组的索引。
*将它们按升序或降序排序。
*@param orderDesc排序顺序。下降为true,上升为false。
*/
私有void calculateDistributionRanks(布尔orderDesc){
//将分馏比率数组复制到另一个tmp数组。注意:-使用分馏比率以便排名更准确。
float[]tmp=Arrays.copyOf(分数比率,无方框);
//按升序对数组排序
数组排序(tmp);
//重新初始化rankIndex数组
rankIndex=新整数[框的数量];

对于(inti=0;i,我想到了两种方法

  • 最佳舍入

    把这个问题当作一个最优的取整问题来处理
    static int[] distribute(int[] boxes, int items) {
        int[] result = new int[boxes.length];
        int sumSoFar = 0;
        int totalCapacity = 0;
        for (int box : boxes) {
            totalCapacity += box;
        }
        float R = (float) items / totalCapacity;
    
        for (int i = 0; i < boxes.length - 1; i++) {
            int box = boxes[i];
            result[i] = Math.round(R * box);
            sumSoFar += result[i];
        }
        result[boxes.length - 1] = items - sumSoFar;
        return result;
    }
    
    System.out.println(Arrays.toString(distribute(new int[]{1, 2}, 10)));
    System.out.println(Arrays.toString(distribute(new int[]{4, 12}, 8)));
    
    [3, 7]
    [2, 6]