使用每一行的二维数组中小于或等于 k ​​的最大可能总和

Posted

技术标签:

【中文标题】使用每一行的二维数组中小于或等于 k ​​的最大可能总和【英文标题】:Maximum possible sum less than or equal to k in a 2D array using each row 【发布时间】:2015-10-12 12:38:28 【问题描述】:

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

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

这是一个程序的 sn-p,我无法实现每行和 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:Rows = 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;
    



【问题讨论】:

矩阵有多少行?如果它的行数少于 M 怎么办?我们能满足条件吗? @svs 行总是等于 M ,即。 e 必须从每一行中选择一个元素 有什么限制吗? K 和 M 有多大? @PhamTrung 1 ≤ M ≤ 100 1 ≤ K ≤ 10000 【参考方案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)。

【讨论】:

对于二维数组值 = 2,3,4,2,3,4,2,3,4 , K=10,M=3 ,答案应该是 10(2+4+4) 而你的解决方案是 8。 感谢您的提醒,我最终使用 dfs 方法解决了解决方案,请查看我的代码并查看它。我已经编辑了线程并添加了代码。 @shubhamr:可能您在翻译中犯了一些错误,因为答案中的算法正确解决了该测试用例(请参阅编辑,我只是​​添加了输入数据和调用)。跨度> 知道了,非常感谢。【参考方案2】:

蛮力方法:

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 拥有每一行的当前选择。

【讨论】:

【参考方案3】:

这可以使用布尔二维表来解决。 dp[r][s] 的值设置为 true,如果可以生成 sum 's' ,则使用恰好 'r' 行(即 [0 到 r-1] 行中的每一行中的一个元素)。使用这个 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 表来解决它

【讨论】:

以上是关于使用每一行的二维数组中小于或等于 k ​​的最大可能总和的主要内容,如果未能解决你的问题,请参考以下文章

O(N)求数组中小于等于K的最大子数组长度

算法总结之 未排序数组中累加和小于或等于给定值的最长子数组长度

找到最大和连续子数组,使得子数组的长度小于等于 k?

每日编程-20170425

动态规划算法:硬币的最大总和(小于或等于k)

2021-08-13:给定一个每一行有序每一列也有序,整体可能无序的二维数组 ,在给定一个正数k,返回二维数组中,最小的第k个数。