如何选择哪个矢量值总和为常数

时间:2018-02-22 23:20:14

标签: c++ vector sum

我做了一个向量,但我不知道如何选择变量来总结一定数量。

以下是代码:

#include <iostream>
#include <vector>

int main(int argc, const char * argv[]) {
    std::vector<int> numbers;
    int en;
    int boy;
    while((std::cout << "EN giriniz: ") && (std::cin >> en))
    {
        numbers.push_back(en); //numbers will resize itself automatically
        while((std::cout << "BOY giriniz: ") && (std::cin >> boy))
        {
            numbers.push_back(boy); //numbers will resize itself automatically
            break;
        }
    }
    for (std::vector<int>::const_iterator i = numbers.begin(); i != numbers.end(); ++i)
        std::cout << *i << ' ';
    //...
}

2 个答案:

答案 0 :(得分:1)

编辑:这是我以前的答案之一。那时我当时并不好,现在我知道这个问题有一个更简单,更快,更少耗费内存的解决方案。如果我们在仅存储最接近的总和的表中自下而上计算DP,我们可以稍后使用我们计算的表值重建其中一个数字子集。

这称为binary knapsack problem。在您的情况下,对象的权重是其值(数字)。

如果你想要一个在O(NW)中运行的快速解决方案,其中N是数字的数量而W是目标值(可以在几分之一秒内完成10,000个数字的问题),请使用维基百科中的动态编程链接。其他一些算法也在那里描述。

对于在O(N2 ^ N)中运行的强力解决方案,基本上,尝试所有可能的数字组合来挑选并记住最佳数字。您可以使用recursion(向下滚动到递归)或者有一个整数的位操作来执行此操作,其中每个位表示是否在集合中包含数字,并且只需递增它。

如果您无法实现它,请参阅我的快速动态编程算法代码:

#include <iostream>
#include <set>
#include <vector>
#include <map>
#include <utility>

using namespace std;

int N, W; //N = number of numbers, W = target sum
vector<int> numbers; //stores the set of numbers

pair<int, multiset<int>> calc(int i, int j) //returns closest sum and best subset of the first i numbers for the target value j
{
    static map<pair<int, int>, pair<int, multiset<int>>> dp; //stores results to avoid repeated calculations
    pair<int, int> p(i, j); //pair for convenience
    if(i == 0) //base case
    {
        return make_pair(0, multiset<int>(
        {}));
    }
    auto findResult = dp.find(p);
    if(findResult != dp.end()) //check if already calculated
    {
        return findResult->second;
    }
    auto temp1 = calc(i - 1, j); //compute result if not using number
    if(numbers[i - 1] > j) //if current number is too big
    {
        return temp1;
    }
    auto temp2 = calc(i - 1, j - numbers[i - 1]); //compute result if using number
    temp2.first += numbers[i - 1];
    temp2.second.insert(numbers[i - 1]);
    pair<int, multiset<int>> result;
    if(temp1.first != temp2.first) //compare results and choose best
    {
        result = temp1.first > temp2.first ? temp1 : temp2;
    }
    else
    {
        result = temp1.second.size() < temp2.second.size() ? temp1 : temp2;
    }
    dp.insert(make_pair(p, result));
    return result;
}

int main()
{
    cout << "Enter the number of numbers: ";
    cin >> N;
    cout << "Enter target sum: ";
    cin >> W;
    numbers.reserve(N); //avoid extra reallocations
    cout << "Enter the numbers: ";
    for(int i = 0; i < N; i++) //input loop
    {
        int temp;
        cin >> temp;
        numbers.push_back(temp);
    }
    pair<int, multiset<int>> result = calc(N, W); //calculate
    //output below
    cout << "The best possible sum is " << result.first << ", obtained using the set of numbers {";
    if(result.second.size() > 0)
    {
        cout << *result.second.begin();
        for(auto i = ++result.second.begin(); i != result.second.end(); i++)
        {
            cout << ", " << *i;
        }
    }
    cout << "}.\n";
}

这是带位操作的简单蛮力(请注意,由于用于存储状态的32位整数,此解决方案只能计算少于32项的解决方案。再花费很长时间才能运行反正):

#include <iostream>
#include <set>
#include <vector>

using namespace std;

int N, W; //N = number of numbers, W = target sum
vector<int> numbers; //stores the set of numbers

int main()
{
    cout << "Enter the number of numbers: ";
    cin >> N;
    cout << "Enter target sum: ";
    cin >> W;
    numbers.reserve(N); //avoid extra reallocations
    cout << "Enter the numbers: ";
    for(int i = 0; i < N; i++) //input loop
    {
        int temp;
        cin >> temp;
        numbers.push_back(temp);
    }
    int bestSum = -1, bestSolution; //stores current best solution
    for(unsigned int current = 0; current < (1 << N); current++) //current represents current set
    {
        int sum = 0;
        for(int i = 0; i < N; i++) //compute sum
        {
            if(current & (1 << i))
            {
                sum += numbers[i];
            }
        }
        if(sum <= W && sum > bestSum) //update best
        {
            bestSum = sum;
            bestSolution = current;
        }
    }
    multiset<int> result; //make result set for output
    int resultSum = 0;
    for(int i = 0; i < N; i++)
    {
        if(bestSolution & (1 << i))
        {
            result.insert(numbers[i]);
            resultSum += numbers[i];
        }
    }
    //output below
    cout << "The best possible sum is " << resultSum << ", obtained using the set of numbers {";
    if(result.size() > 0)
    {
        cout << *result.begin();
        for(auto i = ++result.begin(); i != result.end(); i++)
        {
            cout << ", " << *i;
        }
    }
    cout << "}.\n";
}

一种解决方案,输出所有数字组合,其总和等于最大可能总和不大于目标值并包含尽可能少的数字:

#include <iostream>
#include <set>
#include <vector>
#include <map>
#include <utility>

using namespace std;

int N, W; //N = number of numbers, W = target sum
vector<int> numbers; //stores the set of numbers

pair<int, set<multiset<int>>> calc(int i, int j) //returns closest sum and best subset of the first i numbers for the target value j
{
    static map<pair<int, int>, pair<int, set<multiset<int>>>> dp; //stores results to avoid repeated calculations
    pair<int, int> p(i, j); //pair for convenience
    if(i == 0) //base case
    {
        set<multiset<int>> temp;
        temp.emplace();
        return make_pair(0, temp);
    }
    auto findResult = dp.find(p);
    if(findResult != dp.end()) //check if already calculated
    {
        return findResult->second;
    }
    auto temp1 = calc(i - 1, j); //compute result if not using number
    if(numbers[i - 1] > j) //if current number is too big
    {
        return temp1;
    }
    pair<int, set<multiset<int>>> temp2 = calc(i - 1, j - numbers[i - 1]), newtemp2; //compute result if using number
    newtemp2.first = temp2.first + numbers[i - 1];
    for(const auto k : temp2.second)
    {
        multiset<int> temp = k;
        temp.insert(numbers[i - 1]);
        newtemp2.second.insert(temp);
    }
    pair<int, set<multiset<int>>> *result;
    if(temp1.first != newtemp2.first) //compare results and choose best
    {
        result = temp1.first > newtemp2.first ? &temp1 : &newtemp2;
    }
    else if(temp1.second.begin()->size() != newtemp2.second.begin()->size())
    {
        result =
                temp1.second.begin()->size() < newtemp2.second.begin()->size() ? &temp1 : &newtemp2;
    }
    else
    {
        temp1.second.insert(newtemp2.second.begin(), newtemp2.second.end());
        result = &temp1;
    }
    dp.insert(make_pair(p, *result));
    return *result;
}

int main()
{
    cout << "Enter the number of numbers: ";
    cin >> N;
    cout << "Enter target sum: ";
    cin >> W;
    numbers.reserve(N); //avoid extra reallocations
    cout << "Enter the numbers: ";
    for(int i = 0; i < N; i++) //input loop
    {
        int temp;
        cin >> temp;
        numbers.push_back(temp);
    }
    pair<int, set<multiset<int>>> result = calc(N, W); //calculate
    //output below
    cout << "The best possible sum is " << result.first << ", which can be obtained using a set of "
            << result.second.begin()->size() << " numbers " << result.second.size()
            << " different ways:\n";
    for(const auto &i : result.second)
    {
        cout << '{';
        if(i.size() > 0)
        {
            cout << *i.begin();
            for(auto j = ++i.begin(); j != i.end(); ++j)
            {
                cout << ", " << *j;
            }
        }
        cout << "}\n";
    }
}

答案 1 :(得分:0)

基本上你需要做

n0 + n1 + n2 + n3 + n4 + n5

直到你获胜或者是>目标号码

然后做

n0 + n2 + n3 + ....

没有运气

n0 + n3 + n4 + n5 + n6...

当您用

重新开始列表重启时
n1 + n2 + n3 

然后

 n1 + n3 + n4

这是'简单'又名'蛮力'的方法。其他人会有许多建议的技巧,以加快速度