我出于好奇心正在研究一个研究问题,我不知道如何编写我想到的逻辑。让我向你解释一下:
我有四个载体,比如说,
v1 = 1 1 1 1
v2 = 2 2 2 2
v3 = 3 3 3 3
v4 = 4 4 4 4
现在我想做的是组合添加它们,即
v12 = v1+v2
v13 = v1+v3
v14 = v1+v4
v23 = v2+v3
v24 = v2+v4
v34 = v3+v4
直到这一步它很好。问题是现在我想要从v1,v2,v3,v4中添加这些向量中的每一个,它之前没有添加过。例如:
v3和v4尚未添加到v12,因此我想创建v123和v124。类似地,对于所有的矢量,
v12 should become:
v123 = v12+v3
v124 = v12+v4
v13 should become:
v132 // This should not occur because I already have v123
v134
v14 should become:
v142 // Cannot occur because I've v124 already
v143 // Cannot occur
v23 should become:
v231 // Cannot occur
v234 ... and so on.
重要的是,我不能在一开始就一步到位。例如,我可以做(4选3)4C3并完成它,但我想在每次迭代时一步一步地完成它。
我该如何编程呢?
P.S。:我正在尝试在数据挖掘中使用apriori算法的修改版本。
答案 0 :(得分:9)
在C ++中,给出以下例程:
template <typename Iterator>
inline bool next_combination(const Iterator first,
Iterator k,
const Iterator last)
{
/* Credits: Thomas Draper */
if ((first == last) || (first == k) || (last == k))
return false;
Iterator itr1 = first;
Iterator itr2 = last;
++itr1;
if (last == itr1)
return false;
itr1 = last;
--itr1;
itr1 = k;
--itr2;
while (first != itr1)
{
if (*--itr1 < *itr2)
{
Iterator j = k;
while (!(*itr1 < *j)) ++j;
std::iter_swap(itr1,j);
++itr1;
++j;
itr2 = k;
std::rotate(itr1,j,last);
while (last != j)
{
++j;
++itr2;
}
std::rotate(k,itr2,last);
return true;
}
}
std::rotate(first,k,last);
return false;
}
然后您可以继续执行以下操作:
int main()
{
unsigned int vec_idx[] = {0,1,2,3,4};
const std::size_t vec_idx_size = sizeof(vec_idx) / sizeof(unsigned int);
{
// All unique combinations of two vectors, for example, 5C2
std::size_t k = 2;
do
{
std::cout << "Vector Indicies: ";
for (std::size_t i = 0; i < k; ++i)
{
std::cout << vec_idx[i] << " ";
}
}
while (next_combination(vec_idx,
vec_idx + k,
vec_idx + vec_idx_size));
}
std::sort(vec_idx,vec_idx + vec_idx_size);
{
// All unique combinations of three vectors, for example, 5C3
std::size_t k = 3;
do
{
std::cout << "Vector Indicies: ";
for (std::size_t i = 0; i < k; ++i)
{
std::cout << vec_idx[i] << " ";
}
}
while (next_combination(vec_idx,
vec_idx + k,
vec_idx + vec_idx_size));
}
return 0;
}
**注1:*由于next_combination例程的面向迭代器的接口,也可以使用任何支持通过迭代器进行正向迭代的STL容器,例如std::vector
,{{1} }和std::deque
仅举几例。
注2:此问题非常适合应用备忘录技术。在此问题中,您可以创建一个地图并使用给定组合的矢量和填充它。在计算给定矢量集的总和之前,您可以查找是否已经计算了任何和的子集并使用这些结果。虽然您正在执行非常便宜且快速的求和,但如果您执行的计算要复杂得多且耗时,这种技术肯定会带来一些重大的性能改进。
答案 1 :(得分:2)
我认为这个问题可以通过标记出现哪种组合来解决。
我的第一个想法是你可以使用三维数组来标记发生了什么组合。但那不是很好。
用于标记的位数组(例如整数)怎么样?如:
Num 1 = 2^0 for vector 1
Num 2 = 2^1 for vector 2
Num 4 = 2^2 for vector 3
Num 8 = 2^3 for vector 4
撰写作品时,只需添加所有代表编号即可。例如,向量124将具有值:1 + 2 + 8 = 11.此值对于每个组合都是唯一的。
这只是我的想法。希望它能帮到你。
编辑:也许我对自己的想法不够清楚。我会尝试更清楚地解释一下:
1)为每个向量分配一个代表性的数字。这个数字是矢量的id,它是唯一的。而且,这些数字的每个子集的总和是唯一的,意味着如果我们有k代表数的和是M;我们可以很容易地知道哪些向量参与总和。
我们通过赋值:2 ^ 0表示向量1;向量2为2 ^ 1;向量3为2 ^ 2,依此类推......
每个M = sum(2 ^ x + 2 ^ y + 2 ^ z + ...)=(2 ^ x OR 2 ^ y OR 2 ^ z OR ...)。我们知道向量(x + 1),(y + 1),(z + 1)...参与总和。这可以通过在二进制模式下表示数字来轻松检查。
例如,我们知道:
2 ^ 0 = 1(二进制) 2 ^ 1 = 10(二进制) 2 ^ 2 = 100(二进制) ...
因此,如果我们的总和是10010(二进制),我们知道向量(数字:10)和向量(数字:10000)加在一起。
最好的情况是,这里的总和可以通过“OR”运算符计算,如果用二进制表示数字,也很容易理解。
2)利用上述事实,每次在计算向量总和之前,您可以先添加/或代表他们的代表号码。你可以像查找数组一样跟踪它们。如果总和已经存在于查找数组中,则可以省略它。通过这个你可以解决问题。
答案 2 :(得分:1)
也许我误解了,但这不等于生成1,2,3,4的所有子集(幂集),然后对于幂集的每个元素,对向量求和?例如:
//This is pseudo C++ since I'm too lazy to type everything
//push back the vectors or pointers to vectors, etc.
vector< vector< int > > v = v1..v4;
//Populate a vector with 1 to 4
vector< int > n = 1..4
//Function that generates the power set {nil, 1, (1,2), (1,3), (1,4), (1,2,3), etc.
vector< vector < int > > power_vec = generate_power_set(n);
//One might want to make a string key by doing a Perl-style join of the subset together by a comma or something...
map< vector < int >,vector< int > > results;
//For each subset, we sum the original vectors together
for subset_iter over power_vec{
vector<int> result;
//Assumes all the vecors same length, can be modified carefully if not.
result.reserve(length(v1));
for ii=0 to length(v1){
for iter over subset from subset_iter{
result[ii]+=v[iter][ii];
}
}
results[*subset_iter] = result;
}
如果这是你想到的想法,你仍然需要一个电源设置功能,但如果你搜索电源设置很容易找到该代码。例如, Obtaining a powerset of a set in Java
答案 3 :(得分:0)
但如你所说,最简单的是4C3。
这是用Python编写的东西。你可以将它用于C ++
import itertools
l1 = ['v1','v2','v3','v4']
res = []
for e in itertools.combinations(l1,2):
res.append(e)
fin = []
for e in res:
for l in l1:
aset = set((e[0],e[1],l))
if aset not in fin and len(aset) == 3:
fin.append(aset)
print fin
这将导致:
[set(['v1', 'v2', 'v3']), set(['v1', 'v2', 'v4']), set(['v1', 'v3', 'v4']), set(['v2', 'v3', 'v4'])]
这与4C3的结果相同。