使用每一行的2D阵列中最大可能总和小于或等于k

时间:2015-10-12 12:38:28

标签: c++ algorithm dynamic-programming

给定:二维数组,值K和M

问题:使用所有行(即每行应该有一个元素),使用恰好M个元素找出小于或等于K的最大可能总和。

这是一个程序片段,我无法实现每行和M的条件。

for (int i = 0 ; i<n ; i++)
    for (int s=0; s<M; s++)
        for (int j=K;j>=0;j--)
            if (dp[s][j] && A[i] + j < K)
                dp[s + 1][j + A[i]] = true;

编辑1:行= M,即必须选择每行中的一个元素。

编辑2:动态编程解决方案,感谢@ 6502

ill ret(V(ill) col[101],ill prec[][101],ill s,ill row,ill m,ill k)
{
    if(prec[s][row])
    return prec[s][row];
    else
    {
        if(row==m+1)
        return s;
        ill best=-1;
        int j=row;

        for(int i=0;i<col[j].size();i++)
        {
            if(s+col[j][i] <= k)
            {
                ill x = ret (col,prec,s+col[j][i],row+1,m,k);
                if ((best==-1)||(x>best))
                best=x;

            }
        }
        prec[s][row]=best;
        return best;
    }


}

3 个答案:

答案 0 :(得分:1)

使用动态编程可以解决问题,方法是选择(s, row)对作为状态s是当前总和,row是我们需要包含的下一行。

最大原则是有效的,因为无论我们在前几行中做出哪些选择,结果都只取决于当前总和和当前行索引。

代码(Python)

cache = {}

data = [[2, 3, 4],
        [2, 3, 4],
        [2, 3, 4]]

M = 3
K = 10

def msum(s, row):
    try:
        return cache[s, row]
    except KeyError:
        if row == M:
            return s
        best = None
        for v in data[row]:
            if s+v <= K:
                x = msum(s+v, row+1)
                if best is None or x > best:
                    best = x
        cache[s, row] = best
        return best

print msum(0, 0)

如果不存在解决方案,则函数返回None(即,即使从每行中取最小值,我们最终也超过K)。

答案 1 :(得分:0)

蛮力方法:

bool increase(const std::vector<std::vector<int>>& v, std::vector<std::size_t>& it)
{
    for (std::size_t i = 0, size = it.size(); i != size; ++i) {
        const std::size_t index = size - 1 - i;
        ++it[index];
        if (it[index] > v[index].size()) {
            it[index] = 0;
        } else {
            return true;
        }
    }
    return false;
}

int sum(const std::vector<std::vector<int>>& v, const std::vector<std::size_t>& it)
{
    int res = 0;
    for (std::size_t i = 0; i != it.size(); ++i) {
        res += v[i][it[i]];
    }
    return res;
}

int maximum_sum_less_or_equal_to_K(const std::vector<std::vector<int>>& v, int K)
{
    std::vector<std::size_t> it(v.size());
    int res = K + 1;

    do {
        int current_sum = sum(v, it);
        if (current_sum <= K) {
            if (res == K + 1 || res < current_sum) {
                res = current_sum;
            }
        }
    } while (increase(v, it));
    if (res == K + 1) {
        // Handle no solution
    }
    return res;
}

it包含每行的当前选择。

答案 2 :(得分:0)

这可以使用布尔2D表来解决。 dp [r] [s]的值设置为true,如果它可以使用精确的'r'行(即每个[0到r-1]行中的一个元素)生成sum'''。使用这个dp表,我们可以将下一个状态计算为

              dp[r+1][s] |= dp[r][s-A[r+1][c]]  ; 0 < c < N, 0 < s <= K

其中N是列数(基于0的索引)。最后返回dp表的M-1行中设置的max index的值

以下是自下而上的实施

// Assuming input matrix is M*N
int maxSum() {
    memset(dp, false, sizeof(dp));

    //Initialise base row
    for (int c = 0; c < N; ++c)
        dp[0][A[0][c]] = true;

    for ( int r = 1; r < M; ++r ) {
        for ( int c = 0; c < N; ++c) {
            // For each A[r][c], check for all possible values of sum upto K
            for (int sum = 0; sum <= K; ++sum) {
                if ( sum-A[r][c] >= 0 && dp[r-1][sum-A[r][c]] )
                    dp[r][sum] = true;
            }
        }
    }

    // Return max possible value <= K
    for (int sum = K; sum >= 0; --sum) {
        if ( dp[M-1][sum] )
            return sum;
    }

    return 0;
}

请注意,当前行的dp表值仅取决于前一行,因为这样的空间优化技巧可用于使用1-D表来解决它