按顺序添加最少的元素

时间:2015-10-30 03:37:06

标签: java algorithm

我有一定数量的三元组,我希望以这样的方式将数字相加,即总和保持最小,并且您只能在某个三元组中选择一个数字。例如:

10 10 1   //minimum 1
1  10 21  //minimum 1
10 1  10  //minimum 1 Ans : 1+1+1 = 3

但是不能选择同一列中的相邻元素。

10 10 1 //select 1
10 10 1 //cannot select 1, that's adjacent!
10 10 1 //safe to select 1

但问题是,如果出现平局,我需要扫描序列中的下一个三元组,并确保不选择前一序列中的数字以获得最大利润 例如:

10 10 10  // step 2.select 10 from column 1 or 2
10 10 1   // step 1.make sure not to select element in column 3 in previous sequence
          // step 3. select 1 from column 3

由于我们无法更换扫描仪的位置,因此我无法将扫描仪的readLine移动到之前的位置,我该如何提前扫描?

我的看法:(由于数字范围很大,我使用的是BigInt)

for(long j=0; j<noOfTriples ; j++){
    firstNumber = in.nextBigInteger();
    secNumber = in.nextBigInteger();
    thirdNumber = in.nextBigInteger();

    if(areEqual(firstNumber, secNumber, thirdNumber)){
        while(true){
             firstNumber2 = in.nextBigInteger();
             secNumber2 = in.nextBigInteger();
             thirdNumber2 = in.nextBigInteger();
             noOfTriples--;
                if(areEqual(firstNumber2, secNumber2, thirdNumber2)){
                    count.add(secNumber2); // add any number to the count
                                          // since all of them are same
                }else
                    break;
                }   

    pass(firstNumber, secNumber, thirdNumber, least(firstNumber2, secNumber2, thirdNumber2));
    //pass adds up the minimum of three to the count 
    //where the last field indicates which element to NOT use while adding &
    //least returns minimum of the three
    }else
    pass(firstNumber, secNumber, thirdNumber, -1);  //-1 indicates no bias
}

编辑:

  1. sprinter指出,我需要扫描整个三元组列表。按顺序仅向前扫描1将无济于事。
  2. 输入数量可能高达一百万,因此穷举搜索无济于事。

2 个答案:

答案 0 :(得分:2)

我认为这是动态编程的问题。

让我们保持一个状态F(idx,prev),其中idx表示你所在的当前序列,而prev表示你从前一个序列中添加的项目编号。因此,我们可以根据您的问题陈述迁移到新状态F(idx + 1,new_prev),以使new_prev不等于prev。 伪代码:

F(idx, prev) {

     if ( idx == n+1 ) return 0; //Done with shopping on all N triplets

     ans = INFINITY

     for all item_nums from 1 to 3
            if ( item_nums != prev ) ans = min(ans, cost of item_num in shop_num idx + F(idx+1, item_nums)

    return ans
}

答案 1 :(得分:1)

您似乎假设您只需要提前查看一组,以确定选择哪个当前设置以最小值。这不正确。如果你有(9,3,5),(8,4,7),(6,1,8)然后看前两个你会选择5和4.但是一旦你考虑第三组,那么你会看到你应该选择7和3,这样你就可以选择1.事实上,因为最后一组可以有任意大的数字,你实际上并不知道选择正确的选项,直到你看到所有集。

所有这些的结论是,您需要使用更复杂的算法来最小化总和。鉴于您有许多项目,无法进行详尽的搜索。但是,让我们从这开始,这样你就可以看到它的样子:

假设您已阅读所有输入并将其存储在List<List<Integer>>结构中。

int minSum(int index, int previous, List<List<Integer>> inputs) {
    if (index >= inputs.size())
        return 0;
    else
        return IntStream.range(0, 3)
            .filter(n -> n != previousIndex)
            .map(n -> minSum(index + 1, n, inputs)).min();
}

希望您熟悉Java 8并且能够理解此代码。

现在由于性能原因需要修剪搜索空间,因此变得更加复杂。换句话说,你必须避免搜索你可以推断出永远不会导致总数较低的选项。

例如,您有集合(1,8,5),(2,3,6),(4,9,2)。您的算法查看选项1 + 3 + 4并获得总共7个。它看到的下一个值是第一个集合中的8。但显而易见的是,甚至没有必要考虑这个选项,因为它已经大于迄今为止最小的总数(即7),因此包括它在内的任何选项都不可能导致总数减少

希望能够给你足够的暗示。如果你遇到困难,也许就这些类型的修剪算法提出一个单独的问题。

相关问题