循环浏览所有可能的组合组合以获得最高价值

时间:2013-11-09 16:42:29

标签: java algorithm combinatorics mathematical-optimization

我正在整理一个Java小程序,以便在工作中更快,更高效地完成任务。

用户定义需要拆分项目列表的三个组的大小。列表中的每个项目根据放入的三个组中的哪个组具有不同的值。小程序需要显示哪些组合具有最高总值。

实施例: 带列的二维整数数组;项目编号,组1中的值,组2中的值和组3中的值。

16   2   2   5
19   6   0   3
24   1   4   4
25   4   2   3
27   4   2   3
29   3   3   3
31   5   3   1
32   5   2   2

用户定义组1有3个插槽,组2有3个插槽,组3有2个插槽。

小程序应按以下特定顺序显示以下解决方案

Group 1: 19, 31, 32
Group 2: 24, 27, 29
Group 3: 16, 25
OR
Group 1: 19, 27, 32
Group 2: 24, 29, 31
Group 3: 16, 25
OR
Group 1: 19, 31, 32
Group 2: 24, 25, 29
Group 3: 16, 27
OR
Group 1: 19, 25, 32
Group 2: 24, 29, 31
Group 3: 16, 27

我可以通过所有可能的命令管理一种不那么有效的方式运行数组,但它会产生重复的解决方案(即16,25和25,16)。我确信有一种方法可以总结所有可能的组合,甚至不需要改组阵列。我此刻无法绕过它。如果你们有任何方法,我会非常感激。

2 个答案:

答案 0 :(得分:0)

已更新:使用动态编程的新方法


(旧的:)

我认为我们可以使用贪婪的方法。这个想法是:

  1. 找到表格中的最大值。将相应的项目放入相应的组中。
  2. 从表格中删除该项目的相应行。
  3. 当一个组已满时,请删除该组的相应列。
  4. 为了实现上述想法,我们可以使用数组used[]来识别是否使用了一个项目(已经放入一个组),三个最大堆来表示表中的三个值列。堆元素就像(值是键)。假设三个堆是H[0]H[1]H[2]。算法是这样的:

    Init bool array `used[n]` to all false 
    Init heap array `H[3]`
    Init int array `capacity[3]` to required group sizes
    for(int i from 0 to n-1){
        int v = -1, heap_number, item_number;
        for(int j from 0 to 2){
            if(capacity[j] == 0){
                continue;
            }
            while(used[H[j].top().item_number]){
                H[j].pop();
            }
            if(H[j].top().value > v){
                v = H[j].top().value;
                heap_number = j;
                item_number = H[j].top().item_number;
            }
        }
        Assign Item item_number to Group heap_number
        used[item_number] = true;
        capacity[heap_number]--;
    }
    

    这是我的新方法,一种动态编程方法:

    • 假设f[i][j][k]表示组1,2和3的解决方案,每个组分别留有i,j和k个槽。解决方案是三个列表,记录从项目到组的分配。假设a = i + j + k
    • 州过渡等式:f[i][j][k] = max{f[i-1][j][k] + Item[a].value_1, f[i][j-1][k] + Item[a].value_2, f[i][j][k-1] + Item[a].value_3}
    • 初始状态:f[0][0][0] = 0
    • 最终答案:f[group_1_size][group_2_size][group_3_size]

答案 1 :(得分:0)

我无法想出一个解决方案,但回答你的问题 - 关于运行所有可能的总和 - 你可以使用递归。

// @row - currently processed row
// @g1, g2, g3 - arrays with numbers of rows put in respective group
// @options - for results
// @rows - source array
void PROCESS_ROW(int row, int[] g1, int[] g2, int[] g3, int[][][][] options, rows) {
    if (row >= rows.length) {
        // Recursion ended, collecting generated distribution
        options[].push_back(new int[3][][]);
        options[last][0] = g1.clone();
        options[last][1] = g2.clone();
        options[last][2] = g3.clone();
        return;
    }
    // Trying to put row in each group consequently
    if (g1.length < g1_slots) {
        g1.push_back(row);
          PROCESS_ROW(row + 1, g1, g2, g3, options, rows);
        g1.pop_back();
    }
    if (g2.length < g2_slots) {
        g2.push_back(row);
          PROCESS_ROW(row + 1, g1, g2, g3, options, rows);
        g2.pop_back();
    }
    if (g3.length < g3_slots) {
        g3.push_back(row);
          PROCESS_ROW(row + 1, g1, g2, g3, options, rows);
        g3.pop_back();
    }
}

int[][] rows;
// .. fill
int[][][][] options;

PROCESS_ROW(0, new int[], new int[], new int[], options, rows);
// now options contains all possible groupings

实际上,这段代码不是Java,因此需要进行调整。此外,还必须传递g1_slots等作为参数,但它的详细信息。这个想法是可以理解的。此外,很有可能在第一if部分中包括更强的处理,计算总和并存储最高的一个以及可能的组合。每次遇到更高的总和时清除数组 当然,这个解决方案意味着行有数字0,1,2 ..,16,19,25的内容......所以,应该再次调整这个方面,使用Map rows而不是数组。但正如我所说,它的细节。

相关问题