用一些S计数大小为k的唯一子集
Count unique subsets of size k with some S
七队面对一个可怕的敌人。他只有在特殊情况下才能被击败力量的四重组合攻击(1<=S<=10^9)。鸣人、佐助、小樱和卡卡西必须同时攻击执行组合。它们中的每一个可以从N(1<=N<=1000)个攻击中进行选择,每个攻击具有强度si(0<=i<N,1<=si<=10^9)。个人攻击的力量加起来形成组合的强度。
他们可以使用有效的组合吗?请注意所有人都可以使用攻击。
您需要编写一个函数,该函数接受如下输入——整数
N
作为攻击次数,整数向量s[]
作为N
攻击的强度和整数S
作为所需强度组合的。将输出变量设置为不同的有效数量combo。如果两种组合的强度相差至少使用了一次攻击。
输入:1 {1} 4
输出:1 ===>{1,1,1,1}
输入:2 {1,2} 5
输出:1 ===> {1,1,1,2}
下面是我的代码,它只通过了10个测试用例中的3个。我不知道测试用例,因为它是一些在线代码提交。
我的算法:1) 创建一个散列,其中索引是输入数组中成对的总和,值是对总和有贡献的单个元素2) 在散列上迭代,看看散列中的i是否有k-i3) 计数以上索引和返回计数/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;
}
UPD。我的上帝,现在我已经理解了你的评论:)并看到你试图用我写的方式解决它。不管怎样,我希望你会发现我的一些解释很有用。首先,您不使用散列函数(我知道身份函数是散列函数,但在我们的情况下不是好的)
我也不理解你的count
逻辑。。。我认为您需要再次阅读Two combinations are different if they differ in strength of at least one attack used.
部分,并检查您的count
逻辑。
这只是我的第一个想法。希望能有所帮助。
===================================
你知道,这个问题是关于集合中4个数字的特定和。让我们想象一下,我们只有两个英雄(所以我们的总和中有两个术语):
a + b = S,
其中,a、b是来自N个数字集的攻击强度(我们将其命名为T)。不同的a + b
和的数目是N^2。简单地计算所有这些和,然后搜索那些等于S的和,并不能给我们很好的解决方案。这个问题可以用更好的复杂性来解决。
如果我们能找到一个快速函数,这样:
F(a) = F(S - b)
我们将预先计算所有的F(S-b),然后在所有的a
上循环,并找到哪些满足上面的等式。你提到了哈希。哈希函数可以做到这一点。我们需要这样的散列函数来映射从集合T
到范围[0,N]的所有数字。因为我们只有不超过N个不同的a
但我们有一个小问题:
- CCD_ 16只是意味着CCD_ 17可以等于CCD_。幸运的是,这不是什么大问题
- 因为主功率是:CCD_ 19表示CCD_
好的,正如你所看到的,我们有算法来解决具有摊销O(N)复杂性的a + b = S
问题。听起来不错,很有希望,对吧?:)
===================================
现在回到你的问题:
a + b + c + d = S
我的想法是用O(N^2)预先计算所有f(a + b)
,并像这样存储它们(警告!只是伪代码):
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));
}
我们保持对(a,b)能够恢复初始和的项。然后,如果我们的OurHashFunc是加性的,那么将我们的初始问题转换为这样:
a + b + c + d = S // apply hash func =>
f(a + b) + f(c + d) = f(S) // rename =>
x + y = Z // wow, I bet I've already seen this equation ;)
现在,4项和问题已经简化为2项和问题,开销为O(N^2)。我认为这种减少可以继续:2^k项和问题应该有avg O(N^k)的解。
- 芬威克树(BIT).找到具有给定累积频率的最小索引,单位为 O(logN)
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 堆分配的对象是否存在永不为空的唯一所有者?
- 如何为字符串生成唯一但一致的 N 位哈希(小于 64 位)?
- 最小的CMake构建为Android
- 如何将唯一指针的 std::vector 转换为原始指针的 std::span?
- 将"-01"替换为"-02" 英特尔编译器选项会导致 FPE 在较小的 for 循环行程计数中抛出
- Gtkmm 窗口为空白,不显示任何小部件或标题
- 以下代码如何工作以每次为唯一调用堆栈唯一实例化模板函数?
- 搜索一组点,其长度总和最小为矩形.算法是什么
- 是否有可以将每个双精度转换为唯一uint64_t,保持精度和顺序的功能?(为什么我找不到?
- 如何将目录路径转换为唯一的数字标识符 (Linux/C++)
- 在最小执行时间内找到给定数组中和为零的所有唯一三元组
- 转换为唯一基类指针的向量
- 找出给定长度为100的字符串中的1000个的最小唯一子字符串的长度
- 将QObject连接指定为唯一的正确方法是什么
- 使用OpenMP将循环划分为唯一的任务
- 编译器是否会将给出常量参数的简单函数简化为唯一的指令?
- 类型为唯一项的容器