CodeJam最小标量产品问题

时间:2016-05-21 23:46:57

标签: c++ algorithm stl stl-algorithm

我正在练习这个问题,很快找到了正确的算法,但在实现它时,我遇到了一些奇怪的事情。起初,我意识到我被整数类型的溢出所困,所以开始使用__int64。那是我注意到下一个奇怪的事情。首先,这是我的代码......

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <numeric>

using namespace std;

const string cInputFileName = "E:\\CodeJamInputs\\d-large-practice.in";
const string cOutputFileName = "E:\\CodeJamInputs\\d-large-practice.out.txt";

__int64 FindSmallestProductOfSums(const vector<int> &iVec1, const vector<int> &iVec2)
{
    vector<int> v1 = iVec1;
    vector<int> v2 = iVec2;

    sort(v1.begin(), v1.end());
    sort(v2.begin(), v2.end(), greater<int>());

    __int64 productOfSumsA = inner_product(v1.begin(), v1.end(), v2.begin(), 0);

    __int64 productOfSumsB = 0;
    for(vector<int>::size_type i = 0; i < v1.size(); ++i)
        productOfSumsB += (__int64)v1[i] * (__int64)v2[i];

    return productOfSumsB;
}

int _tmain(int argc, _TCHAR* argv[])
{
    ifstream inputFile(cInputFileName, ifstream::in);
    ofstream outputFile(cOutputFileName, ofstream::out);

    if(inputFile.is_open() && outputFile.is_open())
    {
        int numCases;
        inputFile >> numCases;

        for(int i = 0; i < numCases; ++i)
        {
            int vectorSizes;
            inputFile >> vectorSizes;

            vector<int> vec1, vec2;

            for(int j = 0; j < vectorSizes; ++j)
            {
                int value;
                inputFile >> value;
                vec1.push_back(value);
            }

            for(int j = 0; j < vectorSizes; ++j)
            {
                int value;
                inputFile >> value;
                vec2.push_back(value);
            }

            __int64 smallestProductOfSums = FindSmallestProductOfSums(vec1, vec2);

            outputFile << "Case #" << (i + 1) << ": " << smallestProductOfSums;
            outputFile << endl;
        }
    }

    inputFile.close();
    outputFile.close();
}

所以,正如你所看到的,我对这两个向量进行了两次计算。一个使用STL inner_product,另一个只是手动迭代。那么愚蠢的是,对于问题中的大数据集,inner_product方法会导致错误的返回,而这样做的方法是正确的。踩到STL代码,肯定看起来就像溢出一样,因为Ty Val变量似乎是一个int,当然这是积累的结果。

所以,我想知道的是那些使用inner_product解决了这个问题的人,您认为不同之处是什么?我尝试将0LL作为初始参数传递给giggles,实际上,它确实导致了不同的答案,但仍然不是正确的答案。奇怪的是,在添加显式__int64强制转换之前,它确实产生了与hand方法相同的答案。所以这里肯定会出现类型和溢出的奇怪现象,只是不确定是什么。无论如何,我得到的答案都适用于小型和大型套装,但我只是看到一些人使用了inner_product,我无法让它工作。让我重新说一下...... inner_product适用于小数据集,但不适用于大数据集,因为我的手解决方案适用于小型和大型集合。

以下是问题中每个案例的输出(大数据集共计10个)。对于每种情况,有三个输出。第一个是手动计算方法(正确答案),第二个是使用init为“0”的内部产品(错误答案),第三个是使用“0LL”初始化的内部产品(错误答案)。另外,仅仅是预感,我也编译为x64目标,但结果是一样的。

案例#1:-7839202227936 案例#1:-886912736 案例#1:-1104693507808

案例#2:7999201712083 案例#2:1972606931 案例#2:1127254038483

案例#3:-1313429236847 案例#3:830755729 案例#3:-175262903407

案例#4:-3710387739618 案例#4:464004126 案例#4:-89730309090

案例#5:-3414920765916 案例#5:-421765596 案例#5:-82026144220

案例#6:-1271937742993 案例#6:-627423377 案例#6:-30692194449

案例#7:-1964394407029 案例#7:-1594352757 案例#7:-40249058421

案例#8:-1884282427866 案例#8:1208215078 案例#8:-101871000026

案例#9:-4044533757860 案例#9:1325434972 案例#9:-106048747428

案例#10:-838783451371 案例#10:-1264828651 案例#10:-44214501611

对于长篇文章感到抱歉,但我认为这是一个有趣的问题。

1 个答案:

答案 0 :(得分:0)

CPP reference包含inner_product的示例实现,如下所示:

...
value = value + *first1 * *first2;
...

inner_product涉及两种类型:

  1. 累加器的类型(从传入的初始值推导出,例如0LL)
  2. 要乘的元素的类型(从数组的类型推导出来)
  3. 所以在你的情况下,你有一个int64用于累加器,但只有int(可能是32位数据类型)的元素。当乘法发生时,乘法的结果以32位精度计算!

    因此,有两个可能的溢出位置,一个在+中,一个在*中。更改初始值会修复累加器,但在乘法中仍然存在溢出的风险。

    解决此问题的最简单方法是将输入数组更改为int64而不是int的数组。在这种情况下,乘法将以64位精度完成。