加速处理组合中的 32 位数字(n 中的 k)
我有一个 128 个 32 位数字的列表,我想知道是否有 12 个数字的任意组合,以便所有数字异或后给出 32 位数字,所有位都设置为 1。
所以我从简单的方法开始,采取了像这样的组合生成器:
private static IEnumerable<int[]> Combinations(int k, int n)
{
var state = new int[k];
var stack = new Stack<int>();
stack.Push(0);
while (stack.Count > 0)
{
var index = stack.Count - 1;
var value = stack.Pop();
while (value < n)
{
state[index++] = value++;
if (value < n)
{
stack.Push(value);
}
if (index == k)
{
yield return state;
break;
}
}
}
}
并像这样使用它(data32是给定的32位数字的数组)
foreach (var probe in Combinations(12, 128))
{
int p = 0;
foreach (var index in probe)
{
p = p ^ data32[index];
}
if (p == -1)
{
//print out found combination
}
}
当然,检查所有23726045489546400个组合需要很长时间...... 所以我的问题是 - 我是否在选项中遗漏了一些如何加快检查过程的内容? 即使我在分区中计算组合(例如,我可以启动 8 个线程,每个线程都会检查以数字 0..8 开头的组合),或者通过存储先前计算的组合来加速异或运算 - 它仍然很慢。
PS我希望它在合理的时间内运行 - 分钟,小时而不是几年。 按照评论之一的要求添加号码列表:
1571089837 2107702069 466053875 226802789 506212087 484103496 1826565655 944897655 1370004928 748118360 1000006005 952591039 2072497930 2115635395 966264796 1229014633 827262231 1276114545 1480412665 2041893083 512565106 1737382276 1045554806 172937528 1746275907 1376570954 1122801782 2013209036 1650561071 1595622894 425898265 770953281 422056706 477352958 1295095933 1783223223 842809023 1939751129 1444043041 1560819338 1810926532 353960897 1128003064 1933682525 1979092040 1987208467 1523445101 174223141 79066913 985640026 798869234 151300097 770795939 1489060367 823126463 1240588773 490645418 832012849 188524191 1034384571 1802169877 150139833 1762370591 1425112310 2121257460 205136626 706737928 265841960 517939268 2070634717 1703052170 1536225470 1511643524 1220003866 714424500 49991283 688093717 1815765740 41049469 529293552 1432086255 1001031015 1792304327 1533146564 399287468 1520421007 153855202 1969342940 742525121 1326187406 1268489176 729430821 1785462100 1180954683 422085275 1578687761 2096405952 1267903266 2105330329 471048135 764314242 459028205 1313062337 1995689086 1786352917 2072560816 282249055 1711434199 1463257872 1497178274 472287065 246628231 1928555152 1908869676 1629894534 885445498 1710706530 1250732374 107768432 524848610 2791827620 1607140095 1820646148 774737399 1808462165 194589252 1051374116 1802033814
I have a list of 128 32 bit numbers, and I want to know, is there any combination of 12 numbers, so that all numbers XORed give the 32 bit number with all bits set to 1.
So I have started with naive approach and took combinations generator like that:
private static IEnumerable<int[]> Combinations(int k, int n)
{
var state = new int[k];
var stack = new Stack<int>();
stack.Push(0);
while (stack.Count > 0)
{
var index = stack.Count - 1;
var value = stack.Pop();
while (value < n)
{
state[index++] = value++;
if (value < n)
{
stack.Push(value);
}
if (index == k)
{
yield return state;
break;
}
}
}
}
and used it like that (data32 is an array of given 32bit numbers)
foreach (var probe in Combinations(12, 128))
{
int p = 0;
foreach (var index in probe)
{
p = p ^ data32[index];
}
if (p == -1)
{
//print out found combination
}
}
Of course it takes forever to check all 23726045489546400 combinations...
So my question(s) are - am I missing something in options how to speedup the check process?
Even if I do the calculation of combinations in partitions (e.g. I could start like 8 threads each will check combination started with numbers 0..8), or speed up the XORing by storing the perviously calculated combination - it is still slow.
P.S. I'd like it to run in reasonable time - minutes, hours not years.
Adding a list of numbers as was requested in one of the comments:
1571089837
2107702069
466053875
226802789
506212087
484103496
1826565655
944897655
1370004928
748118360
1000006005
952591039
2072497930
2115635395
966264796
1229014633
827262231
1276114545
1480412665
2041893083
512565106
1737382276
1045554806
172937528
1746275907
1376570954
1122801782
2013209036
1650561071
1595622894
425898265
770953281
422056706
477352958
1295095933
1783223223
842809023
1939751129
1444043041
1560819338
1810926532
353960897
1128003064
1933682525
1979092040
1987208467
1523445101
174223141
79066913
985640026
798869234
151300097
770795939
1489060367
823126463
1240588773
490645418
832012849
188524191
1034384571
1802169877
150139833
1762370591
1425112310
2121257460
205136626
706737928
265841960
517939268
2070634717
1703052170
1536225470
1511643524
1220003866
714424500
49991283
688093717
1815765740
41049469
529293552
1432086255
1001031015
1792304327
1533146564
399287468
1520421007
153855202
1969342940
742525121
1326187406
1268489176
729430821
1785462100
1180954683
422085275
1578687761
2096405952
1267903266
2105330329
471048135
764314242
459028205
1313062337
1995689086
1786352917
2072560816
282249055
1711434199
1463257872
1497178274
472287065
246628231
1928555152
1908869676
1629894534
885445498
1710706530
1250732374
107768432
524848610
2791827620
1607140095
1820646148
774737399
1808462165
194589252
1051374116
1802033814
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不知道C#,我在Python做了一些事情,也许还是很有趣。为您的样品集找到解决方案大约需要0.8秒:
有128c12组合,是2 32 可能的XOR值的550万倍。因此,我尝试保持乐观,只尝试了可能的组合。我将128个数字分为28个块和100个数字,并尝试使用两个块中每个块的六个数字组合。我将第一个块的所有可能的XOR都放入哈希集中,然后浏览第二个块的所有XOR,以找到一个位于该集合的位倒置的XOR。然后,我重建单个数字。
这样,我覆盖(28C6) 2 ×(100c6) 2 = 4.5E14组合,仍然是可能的XOR值的100000倍。因此,可能仍然是找到有效组合的好机会。
Code (
I don't know C#, I did something in Python, maybe interesting anyway. Takes about 0.8 seconds to find a solution for your sample set:
There are 128C12 combinations, that's 5.5 million times as many as the 232 possible XOR values. So I tried being optimistic and only tried a subset of the possible combinations. I split the 128 numbers into two blocks of 28 and 100 numbers and try combinations with six numbers from each of the two blocks. I put all possible XORs of the first block into a hash set
A
, then go through all XORs of the second block to find one whose bitwise inversion is in that set. Then I reconstruct the individual numbers.This way I cover (28C6)2 × (100C6)2 = 4.5e14 combinations, still over 100000 times as many as there are possible XOR values. So probably still a very good chance to find a valid combination.
Code (Try it online!):
根据第一个
1
位的位置将您的数字安排到存储桶中。要将第一个位设置为
1
,您将必须使用相应的存储桶中的奇数项目。...在您重复时,请尝试保持一个不变的领导
1 位正在增加,然后选择将将下一个
0
更改为1
的存储桶,这将大大减少您必须需要的组合数量尝试。Arrange your numbers into buckets based on the position of the first
1
bit.To set the first bit to
1
, you will have to use an odd number of the items in the corresponding bucket....As you recurse, try to maintain an invariant that the number of leading
1
bits is increasing and then select the bucket that will change the next0
to a1
, this will greatly reduce the number of combinations that you have to try.我找到了一个可能的解决方案,它可以适合我的特定任务。
作为简单方法的主要问题,我看到了许多 2E16 组合。
但是,如果我想检查 12 个元素的组合是否等于 0xFFFFFFFF,我可以检查是否存在具有相反值的 6 个元素的 2 种不同组合。
这会将组合数量减少到“仅”5E9,这是可以实现的。
第一次尝试时,我想存储所有组合,然后在大列表中找到相反的组合。但是,在 .NET 中,我找不到存储比 Int32.MaxValue 元素更多的快速方法。
考虑到评论和答案中的位的想法,我决定首先仅存储最左边位设置为 1 的异或和,然后根据定义,我只需要检查最左边位设置为 0 的和 =>存储量减少 2。
最后看来可能会出现许多冲突,因此存在许多具有相同异或和的组合。
当前版本可以找到此类组合,需要在 x64 模式下编译并使用(欢迎任何改进):
I have found a possible solution, which could work for my particular task.
As main issue to straitforward approach I see a number of 2E16 combinations.
But, if I want to check if combination of 12 elements equal to 0xFFFFFFFF, I could check if 2 different combinations of 6 elements with opposit values exists.
That will reduce number of combinations to "just" 5E9, which is achievable.
On first attempt I think to store all combinations and then find opposites in the big list. But, in .NET I could not find quick way of storing more then Int32.MaxValue elements.
Taking in account idea with bits from comments and answer, I decided to store at first only xor sums with leftmost bit set to 1, and then by definition I need to check only sums with leftmost bit set to 0 => reducing storage by 2.
In the end it appears that many collisions could appear, so there are many combinations with the same xor sum.
Current version which could find such combinations, need to be compiled in x64 mode and use (any impovements welcomed):