这是我之前的question关于找到下一位排列的问题。在我看来,我必须修改我的代码以实现与下一位排列类似的东西,但却完全不同。
我在int的位表示中编码有关顶点邻居的信息。例如,如果n = 4
(n - 图形顶点)和图形已满,我的顶点数组看起来像:
vertices[0]=14 // 1110 - it means vertex no. 1 is connected with vertices no. 2, 3, and 4
vertices[1]=13 // 1101 - it means vertex no. 2 is connected with vertices no. 1, 3, and 4
vertices[2]=11 // 1011 - it means vertex no. 3 is connected with vertices no. 1, 2, and 4
vertices[3]=7 // 0111 - it means vertex no. 4 is connected with vertices no. 1, 2, and 3
第一个(主要)for循环是从0到2 ^ n(因为2 ^ n是一组子集的数量)。
因此,如果n = 4
,则有16个子集:
{empty}, {1}, ..., {4}, {0,1}, {0,2}, ..., {3,4}, {0,1,2}, ..., {1,2,3}, {1,2,3,4}
这些子集由for循环
中的索引值表示for(int i=0; i < 2^n; ++i) // i - represents value of subset
我们说n = 4
,实际上是i = 5 //0101
。我想检查一下这个子集的子集,所以我想查一下:
0000
0001
0100
0101
现在我正在生成1位集的所有位置换,然后置换2位置换...依此类推(直到我达到BitCount(5)= 2)并且我只采取我想要的置换(通过if语句) )。这是太多不必要的计算。
所以我的问题是,如何生成所有可能的组合而没有重复(n,k),其中n - 图形顶点和k - i (stated above)
中的位数
我的实际代码(生成所有位排列并选择错误):
for (int i = 0; i < PowerNumber; i++)
{
int independentSetsSum = 0;
int bc = BitCount(i);
if(bc == 1) independentSetsSum = 1;
else if (bc > 1)
{
for(int j = 1; j <= bc; ++j)
{
unsigned int v = (1 << j) - 1; // current permutation of bits
int bc2 = BitCount(j);
while(v <= i)
{
if((i & v) == v)
for(int neigh = 1; neigh <= bc2; neigh++)
if((v & vertices[GetBitPositionByNr(v, neigh) - 1]) == 0)
independentSetsSum ++;
unsigned int t = (v | (v - 1)) + 1;
v = t | ((((t & -t) / (v & -v)) >> 1) - 1);
}
}
}
}
所有这一切都是因为我必须计算n的每个子集的独立集合数。
我想在不创建任何数组的情况下这样做,或者通常我想避免分配任何内存(两个都没有向量)。
一点点解释:
n=5 //00101 - it is bit count of a number i - stated above
,k=3
,集合中的数字(数字表示位位置设置为1)
{
1, // 0000001
2, // 0000010
4, // 0001000
6, // 0100000
7 // 1000000
}
正确的组合是{1,2,6} // 0100011
,但{1,3,6} // 0100101
是错误的组合。在我的代码中,有许多错误的组合,我必须过滤。
答案 0 :(得分:3)
我不确定我是否正确理解了您的确切需求,但根据您的示例(i==5
),您希望获得给定子集的所有子集。
如果是这种情况,您可以直接生成所有这些子集。
int subset = 5;
int x = subset;
while(x) {
//at this point x is a valid subset
doStuff(x);
x = (x-1)⊂
}
doStuff(0) //0 is always valid
希望这有帮助。
答案 1 :(得分:0)
我生成所有可能组合的第一个猜测是以下规则(抱歉,如果它有点难以阅读)
start from the combination where all the 1s are on the left, all the 0s are on the right move the leftmost 1 with a 0 on its immediate right to the right if that bit had a 1 on its immediate left then move all the 1s on its left all the way to the left you're finished when you reach the combination with all the 1s on the right, and all the 0s on the left
对n = 5和k = 3应用这些规则可以得到:
11100
11010个
10110个
01110
11001个
10101个
01101
10011个
01011
00111
但这并不会让我感到非常高效(和/或优雅) 更好的方法是通过仅翻转有限数量的位来找到迭代这些数字的方法(我的意思是,你总是需要翻转O(1)位来达到下一个组合,而不是O(n) ),这可能允许更有效的迭代(有点像https://en.wikipedia.org/wiki/Gray_code) 如果我找到更好的话,我会编辑或发布另一个和。