如何找到最大乘积的总和?

How to find the sum of the maximum product?

提问人:noroong 提问时间:11/9/2023 最后编辑:Remy Lebeaunoroong 更新时间:11/9/2023 访问量:81

问:

当给定 n 个整数时,您可以将两个数字相乘或保持原样。我编写了一个算法来找到所有值加在一起的最大值。

例如,输入为:

9(数组长度) -1 -8 2 1 3 6 -5 0 1

输出需要为 62:

62=-8x-5+0x-1+6x3+2+1+1

如果数组是 ,则答案应为 91。如果数组是 ,则答案应为 838。7 4 1 2 5 3 1 9 0-13 7 -12 13 -8 4 12 7 15 6 -2 10 9 15 4 1 -15

我是这样编写代码的:

#include <iostream>
#include "sop.h"
using namespace std;

sop::sop() {
    this->num = 0;
    this->array = NULL;
}

sop::sop(int* a, int n) {
    this->num = n;
    this->array = new int[n];
    for (int i = 0; i < n; i++) this->array[i] = a[i];
}

sop::~sop() {
    if (this->array) {
        delete[] this->array;
    }
    this->num = 0;
    this->array = NULL;
}

void sop::printArray(void) {
    if (!this->num)  return;
    for (int i = 0; i < num; i++) cout << array[i] << "  ";
    cout << endl;
}

int myMax(int a, int b) {
    return (a > b) ? a : b;
}

int sop::maxSOP() {
    if (num == 0) return 0;
    if (num == 1) return array[0];

    int maxSum = array[0]; // Initialize maxSum to the first element
    int currentMax = array[0]; // Initialize currentMax to the first element

    for (int i = 1; i < num; i++) {
        int temp = currentMax; // Store the previous currentMax

        // Calculate the current maximum product including the current element
        currentMax = myMax(array[i], myMax(currentMax * array[i], temp * array[i]));

        // Update maxSum with the maximum of maxSum and currentMax
        maxSum = myMax(maxSum, currentMax);
    }

    return maxSum;
}

maxSOP这就是我所做的。myMax

在此代码中,结果是 288,而不是 62。我不知道为什么。你能修复这个代码吗?我将向您展示可以帮助您修复此代码的其他文件。

其他文件.cpp

#include <iostream>
#include <fstream>
#include "sop.h"
using namespace std;

int main(int argc, char* argv[]) {
    int i = 0;
    int num = 0;
    int* array = NULL;
    ifstream fin;
    sop* _sop = NULL;

    if (argc > 1) {
        fin.open(argv[1]);
        if (!fin.is_open()) {
            cerr << "File " << argv[1] << " does not exist!" << endl;
            exit(0);
        }
        fin >> num;
        array = new int[num];
        for (i = 0;i < num;i++)        fin >> array[i];
        fin.close();
    }
    else {
        cin >> num;
        array = new int[num];
        for (i = 0;i < num;i++)        cin >> array[i];
    }

    _sop = new sop(array, num);
    cout << "Input array: ";
    _sop->printArray();
    cout << "Maximum sum of products = " << _sop->maxSOP() << endl;
    delete _sop;
    if (array)       delete[] array;
    array = NULL;
    return 0;
}

otherheader.h

#include <iostream>
#include <fstream>
#include "sop.h"
using namespace std;

int main(int argc, char* argv[]) {
    int i = 0;
    int num = 0;
    int* array = NULL;
    ifstream fin;
    sop* _sop = NULL;

    if (argc > 1) {
        fin.open(argv[1]);
        if (!fin.is_open()) {
            cerr << "File " << argv[1] << " does not exist!" << endl;
            exit(0);
        }
        fin >> num;
        array = new int[num];
        for (i = 0;i < num;i++)        fin >> array[i];
        fin.close();
    }
    else {
        cin >> num;
        array = new int[num];
        for (i = 0;i < num;i++)        cin >> array[i];
    }

    _sop = new sop(array, num);
    cout << "Input array: ";
    _sop->printArray();
    cout << "Maximum sum of products = " << _sop->maxSOP() << endl;
    delete _sop;
    if (array)       delete[] array;
    array = NULL;
    return 0;
}
C++ 算法 数据结构 时间复杂度

评论

3赞 drescherjm 11/9/2023
在此代码中。 结果是 288 而不是 62 我不知道为什么。找出代码出现意外行为的原因的一种快速简便的方法是使用一个简单的示例,并在执行每行代码后使用调试器逐行查看变量和流,直到代码执行您意想不到的操作。

答:

3赞 Atmo 11/9/2023 #1

基本上,如果您能够有效地将数字配对在一起,您将获得最高的总和。我建议以下规则:

  1. 数字 <= 0 应该配对在一起。
    对于 和 , .
    与配对相反:这不是我们想要的配对。
    n1 <= 0n2 <= 0n1 * n2 >= n1 + n2n1 <= 0n2 > 0n1 * n2 < n1 + n2
  2. 1永远不应该配对。
    同上:如果我们与 1 配对,则结果乘积将始终小于 。
    nn+1
  3. 数字 > 1 应该配对在一起。
    不管你选择什么,(只有当两边相等时;在其他情况下,这是一个严格的不等式)。
    n1 > 1n2 > 1n1 * n2 >= n1 + n2n1 = n2 = 2
  4. 当您有超过 2 个可以配对的数字时(如上述 3 条规则所述),请务必先选择更高的绝对值。
    3 个整数的示例:

    类似的东西也适用于 4 个整数 :您可以构建的最大组合是 。
    1 < n1 <= n2 <= n3n2 * n3 + n1 >= n1 * n3 + n2 >= n1 * n1 + n3 >= n1 + n2 + n31 < n1 <= n2 <= n3 <= n4n1 * n2 + n3 * n4

这几乎使我们走上了正轨;我们必须:

  1. 对数字进行排序(因为规则 4)
  2. 将列表分为 3 个部分(因为规则 1、2、3)。在每一步中,我们首先成对处理项目(即将迭代器增加 2),然后如果该段的元素数量为奇数,我们将最小的(绝对值)剩余项目添加到总和中。
    该算法看起来有点不对称,因为 预计 位于向量的中间,因此我们将在负数循环之后处理它们(而不是从 重新启动)。
    1numbers.begin()
#include <algorithm>
#include <vector>
int main(int argc, char* argv[])
{
    //std::vector<int> numbers{ -1, -8, 2, 1, 3, 6, -5, 0, 1 };
    //std::vector<int> numbers{ 7, 4, 1, 2, 5, 3, 1, 9, 0 };
    std::vector<int> numbers{ -13,  7, -12,  13, -8,  4,  12,  7,  15,  6, -2,  10,  9,  15,  4,  1, -15 };

    int sum = 0;
    std::sort(numbers.begin(), numbers.end());
    {
        //Start with numbers <= 0 
        auto iter1 = numbers.begin(), iter2 = iter1 + 1;
        for (; iter2 != numbers.end() && *iter2 <= 0; iter2 += 2) {
            sum += *iter1 * *iter2;
            iter1 += 2;
            if (iter1 == numbers.end())
                break;
        }
        //Process the 1's
        for (;iter1 != numbers.end() && *iter1 <= 1; ++iter1)
            sum += *iter1;
    }
    {
        //Process numbers > 0 (using a reverse iterator)
        auto iter1 = numbers.rbegin(), iter2 = iter1 + 1;
        for (; iter2 != numbers.rend() && *iter2 > 1; iter2 += 2) {
            sum += *iter1 * *iter2;
            iter1 += 2;
            if (iter1 == numbers.rend())
                break;
        }
        if (iter1 != numbers.rend() && *iter1 > 1)
            sum += *iter1;
    }
    std::cout << sum << std::endl;

    return 0;
}

我允许您添加回所有要将用户输入推送到的行。numbers

如果您想知道,复杂性是因为初始排序。O(n log(n))

评论

0赞 Toby Speight 11/9/2023
这很好地演示了原理,但需要一些工作才能完成它,因为当我们的数字都是正数或全负数时,可以是 UB。OP 应该添加一套很好的测试来清除剩余的错误。iter2 += 2
0赞 Atmo 11/9/2023
这是一个很好的观点,我花了比我预期的更长的时间来写我的答案,我想我有点太匆忙了。现在它已更正 + 在我使用它时添加了小细节。