简体   繁体   English

需要帮助优化动态规划问题解决方案

[英]Need help to optimize dynamic programming problem solution

The problem statement:问题陈述:

Given two arrays a and b with sizes n and m respectively.给定两个 arrays ab ,大小分别为nm All numbers in these arrays are in the range of 0 to 9 inclusive.这些 arrays 中的所有数字都在 0 到 9 的范围内。 Lets create a matrix with size of nxm where values in row i and column j is equal to ai * 10^9 + bj .让我们创建一个大小为nxm的矩阵,其中第i行和第j列的值等于ai * 10^9 + bj Find the path from square 1,1 to n,m with the maxium sum.找到从方块1,1n,m的路径,总和最大。 You're allowed to move forward or down.你可以向前或向下移动。

Input parameters: The first line contains n and m (1 <= n, m <= 100 000)输入参数:第一行包含nm (1 <= n, m <= 100 000)

The second line contains values of array a第二行包含数组a

The third line contains values of array b第三行包含数组b的值

Output Print the maximum sum Output 打印最大总和

Time limit: 1 second时间限制:1秒

Memory limit: 512MB Memory 限制:512MB

Example:例子:

input:输入:

7 4
0 7 1 7 6 7 6
4 1 9 7

output: 55000000068 output: 55000000068

在此处输入图像描述

I tried to solve this problem with dynamic programming, but my solution works in O(n * m) and can't pass time limit:我试图用动态规划来解决这个问题,但我的解决方案在O(n * m)中有效并且无法通过时间限制:

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int main() {
        int n, m; cin >> n >> m;

        vector<uint64_t> a(n), b(m);
        for(int i = 0; i < n; i++) {
            int tmp;
             cin >> tmp;
             a[i] = tmp * 10e8;
        }

        for(int i = 0; i < m; i++) cin >> b[i];

        vector<uint64_t> dp(m);
        dp[0] = a[0] + b[0];

        for (int i = 1; i < m; i++)
            dp[i] = dp[i-1] + a[0] + b[i];

        for (int i = 1; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                if (j == 0)
                    dp[j] = dp[j] + a[i] + b[j];
                else
                    dp[j] = max(dp[j], dp[j-1]) + a[i] + b[j];
            }
        }

        cout << dp.back() << endl;

        return 0;
}

It's possible to solve this problem without dynamic programming, and with O(n+m) memory and time requirements.无需动态规划即可解决此问题,并且需要 O(n+m) memory 和时间要求。

As pointed out by @Botje in the comments, the reward for higher values in a is overwhelmingly large.正如@Botje在评论中指出的那样, a中更高值的回报是非常大的。 An optimal path will therefore remain in the leftmost column until it reaches the largest value in a (which is 7 in the above example).因此,最佳路径将保留在最左边的列中,直到它达到a中的最大值(在上面的示例中为 7)。 If this maximum value appears only once in a , then the best option would be to consume the whole of this row, followed by the last elements of all the following rows until we reach the bottom right corner.如果这个最大值在a中只出现一次,那么最好的选择是消耗整行,然后是所有后续行的最后一个元素,直到我们到达右下角。

However, if this maximum value appears more than once, we can get a better score by moving right along the first row with the maximum value of a until we reach a column with the maximum value of b , then moving down this column to the last row containing the maximum value of a .但是,如果这个最大值出现不止一次,我们可以通过沿着具有最大值a的第一行向右移动直到我们到达具有最大值b的列,然后将该列向下移动到最后一个来获得更好的分数包含a最大值的行。 We can then consume the rest of this row followed by the last elements of all following rows as before.然后,我们可以像以前一样使用此行的 rest,然后是所有后续行的最后一个元素。

Perhaps an illustration will help:也许一个例子会有所帮助:

    a = [ 0, 6, 9, 9, 0, 9, 3, 1 ]
    b = [ 1, 3, 2, 8, 4, 8, 1, 6 ]

   Col:  0     1     2     3     4     5     6     7
  Row:
   0    0,1   0,3   0,2   0,8   0,4   0,8   0,1   0,6 
         v
   1    6,1   6,3   6,2   6,8   6,4   6,8   6,1   6,6 
         v 
   2    9,1 > 9,3 > 9,2 > 9,8   9,4   9,8   9,1   9,6 
                           v
   3    9,1   9,3   9,2   9,8   9,4   9,8   9,1   9,6 
                           v
   4    0,1   0,3   0,2   0,8   0,4   0,8   0,1   0,6 
                           v
   5    9,1   9,3   9,2   9,8 > 9,4 > 9,8 > 9,1 > 9,6 
                                                   v
   6    3,1   3,3   3,2   3,8   3,4   3,8   3,1   3,6 
                                                   v
   7    1,1   1,3   1,2   1,8   1,4   1,8   1,1   1,6 

In this example, there are three rows where a = 9, which are rows 2, 3 and 5. To get the maximum score, we need to follow the first of these rows (ie row 2) until we reach the column with the maximum value of b (either column 3 or column 5, it makes no difference).在这个例子中,有三行a = 9,分别是第 2、3 和 5 行。为了获得最大分数,我们需要跟随这些行中的第一行(即第 2 行),直到到达最大值的列b的值(第 3 列或第 5 列,没有区别)。 Then move down to the last row where a =9 (row 5), step right to the end of this row, and finally down to the bottom right corner.然后向下移动到a = 9的最后一行(第5行),向右移动到这一行的末尾,最后向下移动到右下角。

I've converted the Python code from an earlier version of this answer into C++. In tests with 10 5 random values in arrays a and b , it produces a result in about 0.3 seconds on my system.我已将此答案的早期版本的 Python 代码转换为 C++。在 arrays ab中使用 10 5 个随机值进行的测试中,它在我的系统上大约 0.3 秒内产生结果。 The dynamic programming solution above gives identical results, but takes about 4 minutes:上面的动态规划解决方案给出了相同的结果,但需要大约 4 分钟:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;

    vector<int64_t> a(n), b(m);
    int tmp, astart, aend, bmax, i, j;
    
    // Read in arrays a[] and b[]. At the same time,
    // find the first and last indices of the maximum
    // value in a[] (astart and aend) and any index
    // corresponding to the maximum value of b[] (bmax)
    
    for (tmp = -1, i = 0; i < n; i++) {
        cin >> a[i];
        if (a[i] >= tmp) {
            aend = i;
            if (a[i] > tmp) {
                astart = i;
                tmp = a[i];
            }
        }
        a[i] *= 1000000000LL;
    }
    for (tmp = -1, j = 0; j < m; j++) {
        cin >> b[j];
        if (b[j] > tmp) {
            tmp = b[j];
            bmax = j;
        }
    }
    
    // Trace through the matrix. First work down as far as
    // astart, then right until column bmax. Then work down
    // as far as row aend, add the remaining elements in this
    // row, and finally add the last element of each remaining
    // rows until we reach the bottom right corner.
    
    i = j = 0;
    int64_t tot = a[i] + b[j];
    while (i < astart) tot += a[++i] + b[j];
    while (j < bmax) tot += a[i] + b[++j];
    while (i < aend) tot += a[++i] + b[j];
    while (j < m-1) tot += a[i] + b[++j];
    while (i < n-1) tot += a[++i] + b[j];
        
    cout << tot << endl;
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM