我们如何有效地解决给定的场景?

时间:2016-02-05 15:01:00

标签: algorithm dynamic-programming

我们有一个迷宫,我们需要尽可能多地访问房间。迷宫的特色是,一旦你进入任何一个房间,它只会带你到你移动方向有更高标签的房间。 B和C决定向相反的方向移动,试图运气,以最大化他们搜索的房间数量。(他们可以从任何房间开始,不必相同)

我们需要找出可以搜索的最大房间数。

1. Access to any room with a higher tag is allowed, not just adjacent rooms or the next room with a higher tag. 
2. Tags are unique. 

所以给出了输入:

12 11 10 1 2 3 4 13 6 7 8 5 9 
the answer is 12: (1,2,3,4,6,7,8,9) for B and (5,10,11,12) for C.

我想到使用最长的子序列从右到左然后从左边解决这个问题。上面两个子序列中的唯一元素的数量就是答案。

但我的逻辑似乎失败了,怎么办呢?

2 个答案:

答案 0 :(得分:1)

我认为诀窍在于交叉点,其中B和C可能共享一个值或者有选项可以解决这个问题(比如序列是12 11 10 1 2 3 4 <3 5> 13 6 7 8 9这里的额外数字会给解决方案增加1,但不会t改变最长的子序列的结果。

所以唯一的问题是中间的一个房间,因为两边的数值都不同。

我要做的是:在一个方向上做最长的子序列,找出解决方案(任何解决方案),取出解决方案中的数字,并在另一个方向上执行最长的子序列。这样,如果在中间穿过房间的方式,第二次通过将更喜欢它,除非确实需要所选择的数字。要检查是否做同样的事情,但是在最初选择的方向上构建相反方向的第一个子序列和第二个子序列(在删除解决方案之后)。

复杂性仍为O(N),但常数因子略高。

答案 1 :(得分:1)

我的程序在下面计算搜索到的最大房间数。这具有O(n ^ 3)的时间复杂度。我修改了DP算法,用于计算在线可用的最长增长序列,以解决OP的问题。这也解决了OP对像{1,4,6,2,5}这样的数组的关注。我正确地将上一个示例的最大值设为5。所以,我使用@BeyelerStudios的想法,我们需要从左到右和从右到左计算最长的增长子序列。但是,有一个警告。如果我们计算从左到右的最大序列,则从右到左的序列应该在剩余的元素上。示例:
对于数组{1,4,6,2,5}。如果选择的前方房间是{1,4,5},那么应该在左边的元素{6,2}上计算反向最长的增加序列。

以下是我的计划:

#include <iostream>
using namespace std;


// compute the max increasing sequence from right to left.
int r2lRooms (int arr[], int n) 
{

    int dp[n];
    int i =0, j = 0;
    int max = 0;

    for ( i = 0; i < n; i++ ) {
        dp[i] = 1;
    }

    for (i = n-2; i >= 0; i--) {
        for ( j = n-1; j > i; j-- ) {
            if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
                dp[i] = dp[j] + 1;
            }
        }
    }

    for ( i = 0; i < n; i++ ) {
        if ( max < dp[i] ) {
            max = dp[i];
        }
    }
    return max;

}


// compute max rooms.
int maxRooms( int arr[], int n )
{

    int dp[n], revArray[n];
    int i =0, j = 0, k = 0;
    int currentMax = 0;
    int forwardMax = 0, reverseMax = 0;

    for ( i = 0; i < n; i++ ) {
        dp[i] = 1;
    }

    // First case is that except for first elem, all others are in revArray
    for (i=1; i < n; i++, k++) {
        revArray[k] = arr[i];
    }
    reverseMax = r2lRooms (revArray, k);
    forwardMax = 1;
    if (currentMax < (forwardMax + reverseMax)) {
        currentMax = forwardMax + reverseMax;
    }
    cout << "forwardmax revmax and currentmax are: " << forwardMax << " " << reverseMax << " " << currentMax << endl;
    cout << endl;

    for ( i = 1; i < n; i++ ) {
        k = 0;
        forwardMax = 1;
        reverseMax = 0;

        cout << "Forward elems for arr[" << i << "]=" << arr[i] << endl;

        for ( j = 0; j < i; j++ ) {
            if ( arr[i] > arr[j] && dp[i] < dp[j] + 1) {
                dp[i] = dp[j] + 1;
                forwardMax = dp[i]; 
                cout << arr[j] << " ";
            }
            else {
                // element was not in DP calculation, so put in revArray.
                revArray[k] = arr[j];
                k++;
            }
        }
        // copy the remaining elements in revArray.
        for ( j = i+1; j < n; j++ ) {
            revArray[k] = arr[j];
            k++;
        }
        cout << endl;
        reverseMax = r2lRooms (revArray, k);
        if (currentMax < (forwardMax + reverseMax)) {
            currentMax = forwardMax + reverseMax;
        }
        cout << "forwardmax revmax and currentmax are: " << forwardMax << " " <<  reverseMax << " " << currentMax << endl;
        cout << endl;
    }
    cout << " Max rooms searched " << currentMax << endl;
    return currentMax;
}

int main (void) {

    int arr[] = {12, 11, 10, 1, 2, 3, 4, 13, 6, 7, 8, 5, 9 };
    int size = sizeof(arr) / sizeof(int);

    cout << maxRooms (arr, size);


}