使用每一行的二维数组中小于或等于 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 的最大可能总和的主要内容,如果未能解决你的问题,请参考以下文章
算法总结之 未排序数组中累加和小于或等于给定值的最长子数组长度
2021-08-13:给定一个每一行有序每一列也有序,整体可能无序的二维数组 ,在给定一个正数k,返回二维数组中,最小的第k个数。