使用一些S计算大小为k的唯一子集

时间:2014-10-17 13:33:55

标签: c++ algorithm subset-sum

  

7队面对一个可怕的敌人。他只能被特殊的击败   强度的四重组合攻击(1 <= S <= 10 ^ 9)。   火影忍者,佐助,樱花和卡卡西必须同时攻击   执行组合。它们中的每一个可以选择N(1≤N≤1000)攻击,每个具有强度si(0 <= i      

他们可以使用有效的组合吗?请注意相同   所有人都可以获得攻击。

     

您需要编写一个输入如下的输入函数 - An   整数N为攻击次数,整数向量为s[]   N攻击的强度和整数S作为所需的强度   组合。将输出变量设置为distinct有效数   连击。

     

如果它们的强度至少不同,则两种组合是不同的   使用了一次攻击。

输入:1 {1} 4

输出:1 ===>{1,1,1,1}

输入:2 {1,2} 5

输出:1 ===> {1,1,1,2}

以下是我的代码,它只通过了10个测试用例。我不知道测试用例,因为这是一些在线代码提交。

我的算法: 1)创建一个散列,其中索引作为输入数组和值的对的总和,作为对sum有贡献的单个元素 2)迭代哈希,看看哈希中是否有k-i 3)计算上面的索引并返回计数/ 2,因为我们计算H(i)和H(k-i)

请查看代码并告诉我您认为代码无法生成的场景o / p。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>

const int noOfPalyers = 4;

int validCombo(int input1,int input2[],int input3)
{
    //Write code here
    int count = 0;
    std::vector<int> vec;
    int size =input1*noOfPalyers;
    for(int i = 0; i < input1; i++)
    {
        for(int j = 0; j < noOfPalyers;j++)
        {
            vec.push_back(input2[i]);
        }
    }

    std::vector< std::set< std::pair<int, int> > > vecHash;
    //vecHash.reserve(size*size);

    for(int i =0; i < (size*size); i++)
    {
        vecHash.push_back(std::set< std::pair<int, int> >());
    }

    for(int i =0; i < size; i++)
    {
        for(int j =1; j < size; j++)

        {
            int key = vec[i] + vec[j];
            if(vec[i]<= vec[j])
                vecHash[key].insert(std::make_pair(vec[i], vec[j]));
            else
                vecHash[key].insert(std::make_pair(vec[j], vec[i]));

        }
    }

    for(int i = 0; i < input3; i++)
    {
        if(vecHash[i].size() > 0 &&  i < input3)
        {
            if(vecHash[input3-i].size() > 0)
            {
                std::set< std::pair<int, int> >::iterator iter, iter2;
                for(iter=vecHash[i].begin(); iter!=vecHash[i].end();++iter)
                {

                    for(iter2=vecHash[input3-i].begin(); iter2!=vecHash[input3-i].end();++iter2)
                    {
                        std::cout<<(*iter).first<<","<< (*iter).second<<",";
                        std::cout<<(*iter2).first<<","<< (*iter2).second;
                        std::cout<<"\n";
                        count++;
                    }

                }
            }
        }
    }

    return (count ==1 ? count: count/2);

}

int  main()
{
    int i = 3;
    int arr[] = {1,2,3};
    int j = 7;
    int arr1[] ={1};
    std::cout <<"o/p == "  << validCombo(i, arr, j)<< "\n";
    std::cout <<"o/p == "  << validCombo(1, arr1, 4);


    //getch();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

<强> UPD 即可。我的上帝,现在我已经理解了你的评论:)并且看到你试图像我写的那样解决它。无论如何,我希望你能找到一些有用的解释。首先,你不使用哈希函数(我知道身份函数是一个哈希函数,但在我们的例子中不是好的函数)。
我也不理解你的{{1} } logic ...我想你需要再次阅读count部分并检查你的Two combinations are different if they differ in strength of at least one attack used.逻辑。

只是我的第一个想法。希望它可能会有所帮助。

==================================

你知道,这个问题是关于从集合中得到4个数字的特定总和。让我们想象一下,我们只有2个英雄(总和中有两个词):

count

其中a,b是来自N个数字组的攻击强度(让我们将其命名为T)。不同a + b = S, 和的数量是N ^ 2。简单计算所有这些总和,然后搜索那些等于S的那些并不能给我们提供很好的解决方案。这个问题可以通过更好的复杂性来解决。

如果我们能找到一个快速的功能:

a + b

我们会预先计算所有F(S - b),然后循环遍历所有F(a) = F(S - b) 并找到哪些满足上述等式。你提到哈希。散列函数可以做到这一点。我们需要这样的哈希函数来将集合a中的所有数字映射到范围[0,N]。因为我们只有不超过N个T&#39; s。
但我们在这里遇到一些问题:

  • a只是意味着F(a) = F(S - b)可以等于a。幸运的是,这不是一个大问题,
  • 因为主要权力是:S - b表示F(a) != F(S - b)

好的,正如您所见,我们有解决a != S - b问题的算法,以及摊销的O(N)复杂性。听起来不错,很有希望,对吧? :)

==================================

现在回到你的问题:

a + b = S

我想用O(N ^ 2)预先计算所有a + b + c + d = S 并将它们存储起来(警告!只是伪代码):

f(a + b)

我们保持对(a,b)能够恢复初始总和的条款。然后,如果我们的OurHashFunc是加法的,那么转换我们的初始问题如下:

vector<int> hash = new vector<int>(with size N)
foreach (a in T)
foreach (b in T)
{
    int x = OurHashFunc(a + b);  // a + b <= 2 * 10^9 so it never overflows int
    if (hash[x] == null)
        hash[x] = new vector<pair<int,int>>
    hash[x].push_back(new pair<int, int>(a, b));
}

现在,4项和问题已经减少到2项和问题,其中O(N ^ 2)开销。 我认为这种减少可以继续:2 ^ k-terms总和问题应该有平均O(N ^ k)解。