给定集合N = {1,...,n}
,请考虑P
的{{1}}不同的预先存在的子集。子集N
的特征是0-1 S_p
向量n
,其中第x_p
个元素是0或1,取决于第i
个元素i
中的项是否属于子集。让我们称这类n
的指标向量。
例如,如果x_p
,子集N={1,2,3,4,5}
用向量{1,2,5}
表示。
现在,给定(1,0,0,1,1)
个预先存在的子集及其关联向量P
。
计算出由向量x_p
表示的候选子集。
检查y
是否已经是y
预先存在的子集中的一部分或P
确实是不属于{的一部分的新子集的最有效方法是什么{1}}个子集?
以下是我可以想到的方法:
(方法1)基本上,我们必须对所有预先存在的集合逐个元素进行检查。伪代码如下:
y
(方法2)我想到的另一种思想是存储指标向量P
s的十进制等效项(此处的指标向量被视为二进制表示形式),并将其与{ {1}}。也就是说,如果for(int p = 0; p < P; p++){
//(check if x_p == y by doing an element by element comparison)
int i;
for(i = 0; i < n; i++){
if(x_pi != y_i){
i = 999999;
}
}
if(i < 999999)
return that y is pre-existing
}
return that y is new
个预先存在的集合的集合为:x_p
,则该集合的存储小数将为y
。如果P
是{ (0,1,0,0,1), (1,0,1,1,0) }
,我们计算{9, 22}
并对照集合y
进行检查。这种方法的好处是,对于每个新的(0,1,1,0,0)
,我们不必对照每个预先存在的集合的12
元素进行检查。我们可以比较十进制数。
问题1.在我看来(方法2)应该比(方法1)更有效。对于(方法2),是否有一种有效的方法(C / C ++中的内置库函数)将{9, 22}
和y
从二进制转换为十进制?这些指标变量的数据类型应该是什么?例如n
或x_p
?
问题2.是否有比(方法2)更有效的方法?
答案 0 :(得分:1)
正如您所注意到的,指标向量和N位整数之间有一个琐碎的同构。这意味着问题2的答案为“否”:用于维护集合和测试集合中成员资格的工具与整数相同(哈希表采用常规方法)。有评论提到,Bloom填充器可以有效地测试成员资格,但存在误报的风险,但Bloom过滤器通常用于比您要查看的数据大得多的数据。
关于您的问题1:方法2是合理的,甚至比您想象的要容易。尽管vector<bool>
并没有为您提供将其转换为整数块的简便方法,但在实现方面,我知道它已经以这种方式实现(C ++标准允许对该特定矢量类型进行特殊处理,这通常是如今被认为是一个错误的决定,但偶尔会带来一些好处)。这些向量是可哈希的。因此,只需保持unordered_set<vector<bool>>
,您将获得可以合理地接近最佳性能的性能。 (如果您在编译时知道N
,则可能更喜欢bitset
而不是vector<bool>
。)
答案 1 :(得分:-1)
方法2可以通过计算给定子集的十进制等效值并使用模数1e9 + 7对其进行散列来进行优化。由于N <= 1000(不会发生碰撞),因此每次生成的十进制数都不同。
#define M 1000000007 //big prime number
unordered_set<long long> subset; //containing decimal representation of all the
//previous found subsets
/*fast computation of power of 2*/
long long Pow(long long num,long long pow){
long long result=1;
while(pow)
{
if(pow&1)
{
result*=num;
result%=M;
}
num*=num;
num%=M;
pow>>=1;
}
return result;
}
/*checks if subset pre exists*/
bool check(vector<bool> booleanVector){
long long result=0;
for(int i=0;i<booleanVector.size();i++)
if(booleanVector[i])
result+=Pow(2,i);
return (subset.find(result)==subset.end());
}