如果有给定的集合,则可以找到列表的最佳组合的算法

时间:2019-04-08 22:13:26

标签: algorithm set subset

我正在寻找一种算法,以找到一组列表的最佳组合(权重最高)。例如,假设我们有项目“ A”,“ B”和“ C”,我们得到4个A,2个B和3个C。一些可能的组合可能是:

{A,B,C},{A,B,C},{A,C},{A}
{A,B},{A,B,C},{A,C},{A,C}

然后权重基于每套物品的数量,例如:

1件:5

2个项目:15

3个项目:20

因此,在这种情况下,第一个组合的权重为20 + 20 + 15 + 5 = 60,第二个组合的权重为15 + 20 + 15 + 15 = 65。贪婪算法在这种情况下不起作用,因为在某些情况下,寻找最大数量的商品并不能返回最佳组合。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我使用递归解决了这个问题。

这些变量定义了问题(静态变量):

private static boolean[] BEST_SOLUTION_SO_FAR = null;
private static int BEST_WEIGHT_SO_FAR = 0;

private static String[][] POSSIBLE_SETS =  {{"A","B","C"},{"A","B","C"},{"A","C"},{"A"},{"A","B"},{"A","B","C"},{"A","C"},{"A","C"}};

private static Map<String, Integer> MAX_OF_EACH_ITEM = new HashMap<>();
static {
    MAX_OF_EACH_ITEM.put("A", 4);
    MAX_OF_EACH_ITEM.put("B", 2);
    MAX_OF_EACH_ITEM.put("C", 3);
}

这是主要方法(它将为递归的开始进行所有设置):

public static void main(String[] args) {
    BEST_WEIGHT_SO_FAR = 0;
    BEST_SOLUTION_SO_FAR = null;

    // start the recursion
    buildSolution(new boolean[POSSIBLE_SETS.length], new HashMap<>());

    // print solution
    System.out.println("BEST SOLUTION : ");
    for (int i = 0; i < POSSIBLE_SETS.length; i++) {
        if(BEST_SOLUTION_SO_FAR[i]){
            System.out.println(Arrays.toString(POSSIBLE_SETS[i]));
        }
    }
}

这是递归方法:

private static void buildSolution(boolean[] isSelected, Map<String, Integer> itemsUsed){
    boolean canBeExpanded = false;
    for (int i = 0; i < isSelected.length; i++) {
        // check whether another set can be added
        if(!isSelected[i]){

            // calculate new numbers of items used
            Map<String, Integer> itemsUsedB = new HashMap<>(itemsUsed);
            for (int j = 0; j < POSSIBLE_SETS[i].length; j++) {
                String key = POSSIBLE_SETS[i][j];
                if(itemsUsedB.containsKey(key))
                    itemsUsedB.put(key, itemsUsedB.get(key) + 1);
                else
                    itemsUsedB.put(key, 1);
            }

            // check whether this is possible
            boolean isPossible = true;
            for(String key : MAX_OF_EACH_ITEM.keySet()){
                if(itemsUsedB.containsKey(key) && itemsUsedB.get(key) > MAX_OF_EACH_ITEM.get(key)){
                    isPossible = false;
                    break;
                }
            }

            // if not possible attempt next
            if(!isPossible)
                continue;

            // mark this solution as expandable
            canBeExpanded = true;

            // mark as selected
            isSelected[i] = true;

            // recurse
            buildSolution(isSelected, itemsUsedB);

            // undo mark
            isSelected[i] = false;
        }
    }
    // a solution that can no longer be expanded was found
    if(!canBeExpanded){
        int w = 0;
        int[] setSizeWeight = {0,5,15,20};
        for (int i = 0; i < isSelected.length; i++) {
            w += isSelected[i] ? setSizeWeight[POSSIBLE_SETS[i].length] : 0;
        }
        if(w > BEST_WEIGHT_SO_FAR){
            BEST_WEIGHT_SO_FAR = w;
            BEST_SOLUTION_SO_FAR = Arrays.copyOf(isSelected, isSelected.length);
        }
    }
}

它输出:

  

最佳解决方案
  [A,B,C]
  [A,C]
  [A,B]
  [A,C]

体重为65。