【问题标题】:Extracting exactly K elements with maximum sum from a 2D array从二维数组中准确提取具有最大和的 K 个元素
【发布时间】:2023-03-14 18:16:02
【问题描述】:

问题陈述

给定一个N*M矩阵和一个整数K,你需要从矩阵中精确地选择K个整数,使得所选择的K个数之和最大。
但这里有一个问题,在从特定行中选择数字时,比如i-th 行,我们只能选择该行的j-th 元素,前提是我们从该行中选择了前 (j-1) 个元素作为好吧。

约束1 <= N <= 501 <= M <= 100; 1 <= K <= N*M; |matrix[i][j]| <= 100
示例:N = 4,M = 4,K = 5

matrix = {  
{1, 2,  3, 4},  
{3, 4,  1, 1},  
{4, 5, 20, 1},  
{1, 2,  3, 4}}; 

预期输出:36(通过从第 2 行中选择 3 和 4 以及从第 3 行中选择 4、5 和 20)。
我的方法:对于每一行,我计算了每一列的前缀总和以及平均值(如preSum[j] / (j+1))并将其存储在maxSum 数组中。然后对数组进行倒序排序,对平均值较高的元素进行贪婪求和,直到找到K个元素。

import java.util.*;
class Solution
{
    public static int getMaximumKSum(int[][] matrix, int N, int M, int K)
    {
        int preSum = 0, MAX = 0;
        RowSum average [] = new RowSum [N*M];
        for (int i=0, z=0; i<N; i++)
        {
            preSum = 0;
            for (int j=0; j<M; j++)
            {
                preSum += matrix[i][j];
                average[z++] = new RowSum(i, j+1, preSum, ((double)preSum/(j+1)));
            }
        }
        Arrays.sort(average, (x, y) -> Double.compare(y.average, x.average));
        //System.out.println( Arrays.toString(average) );

        Set<Integer> row = new HashSet<>();
        for (RowSum S : average)
        {
            if (K <= 0) break; // All `K` elements found!
            if (!row.contains(S.row) && S.n<=K)
            {
                MAX += S.sum;
                row.add(S.row);
                K -= S.n;
            }
        }
        return MAX;
    }
    public static void main(String[] args)
    {
        int N = 4, M = 4, K = 5;
        int [][] matrix = {{1, 2,  3, 4},
                           {3, 4,  1, 1},
                           {4, 5, 20, 1},
                           {1, 2,  3, 4}};
        System.out.println(getMaximumKSum(matrix, N, M, K));
    }
}
class RowSum
{
    int row,n,sum; // rowNo | number of elements | total sum of 'n' elements
    double average; // = sum / n
    RowSum(int a, int b, int c, double d)
    {
        row = a; n = b; sum = c; average = d;
    }
    public String toString()
    { return String.format("(%d*%.2f)", n, average); }
}

我的代码为自定义输入提供了所需的结果,但在提交时,它给出了一个错误的判断。
所以,要么我的方法完全错误(那么请提出一个正确的方法来解决这个问题)或
它在某些边缘情况下失败(然后请提出适当的修改)。谢谢。

【问题讨论】:

  • 矩阵 {{0,99},{50,0},{1,0}} 是否打破了您的贪婪方法?需要 50(因为 (0+99)/2
  • @Nikxp 我想是的,也许我选择的元素不正确。
  • 你能证明使用前缀平均和的正确性吗?
  • 能否详细说明任务描述中的第i个和第j个?
  • @Surt 好的,假设我们要从i=3rd 行中选择 5。因此,由于 5 在j=2th 列中,我们不能单独选择它,因为在 5 之前还有其他元素出现。因此,必须选择 4 和 5。同样,如果我们要选择 20 (a[2][2]),那么我们也必须选择 4 (a[2][0]) 和 5 (a[2][1])。因此,选定的元素将是 4、5 和 20。这同样适用于其他行。

标签: java algorithm data-structures


【解决方案1】:

TL;DR

您的任务看起来类似于背包问题 - 众所周知且复杂的问题。没有已知的多项式算法(来自矩阵长度的多项式)来求解背包。但是因为矩阵中的值是有限的,你可以尝试适应Dynamic programming in-advance algorithm。而且好像是“背包多项选择题”,你可以试试看是solutions


如何将此任务简化为背包问题。

我们将只使用特殊矩阵。每行有一个非零值的矩阵。例如:

matrix = {  
{0, 0, 3, 0},  
{3, 0, 0, 0},  
{0, 0, 20, 0},  
{0, 0, 0, 2}}; 

对于这种类型的矩阵,您的任务是背包问题,其中行中的值是项目的值(价格)。行中非零元素的位置是它的权重。对于第 3 行,我们的商品价值(价格)为 20,重量为 3。

所以如果我们想解决背包问题,我们可以为其创建特殊的矩阵并解决主题的任务。背包是NP-complete,但是NP-Hard还不够,因为这个减少时间取决于物品的重量(感谢@kaya3的报告)

【讨论】:

  • 这不是多项式时间缩减,因为结果矩阵的大小取决于背包问题实例中的
  • @kaya3 对!我的错。感谢反馈
【解决方案2】:

使用

  • 背包 - 动态规划
  • 行位置+1为权重
  • 值是前缀总和。
  • 所以我们有 N*M 项和权重,但每行只能选择一项
  • CR 是遍历矩阵的助手

伪代码(未经测试...)

int [][] matrix = {{1, 2,  3, 4},
                   {3, 4,  1, 1},
                   {4, 5, 20, 1},
                   {1, 2,  3, 4}};
int [N][M] presum;
dict mem = {};

for (i = 0; i < N; i++)
  sum = 0
  for (j= 0; j < N; j++)
    presum[i][j] = sum+matrix[i][j]


CR(col, row, C)
  if (row > 0)
    res = KS(col, row-1, C)
  else if (col > 0)
    res = KS(col-1, M-1, C)
  else 
    res = 0
  return res

KS(col, row, C)
  if (col < 0 || row < 0) || C ==  0) 
    return 0
  if (!mem.find({col,row,C})
    return mem[{col,row,C}]

  if (row+1 > C) # weight is row+1
    row = C # no need to check anything greater than C
    res = CR(col, row, C)
  else
    unused = CR(col, row, C)

    # if used we can't use any more from this row, hence row = 0 in call to CR
    used =   presum[col][row] + CR(col, 0, C - (row + 1))  

    result = max(used, unused)
  
  mem[{col,row,C}] = result

  return result

KS(N-1, M-1, K)

应该是 O(NMK)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    相关资源
    最近更新 更多