【问题标题】:reorganizing a series of 19 bytes into every single combination of any length将一系列 19 个字节重新组织成任意长度的每个组合
【发布时间】:2009-12-31 22:22:54
【问题描述】:

有这19个字节(我要找的是组合而不是组合的数量)

17 00 00 00 A4 EA DB 13 02 00 00 00 00 00 00 A3 D3 02 CC

我需要与这些“规则”相匹配的任何可能的独特组合:

  • 至少 4 个字节长

  • 字节的顺序不能改变(所以 17 A3 D3 02 CC 可以,但 A3 D3 02 CC 17 不行,因为 在原始字符串中 17 是在,但 A3 D3 02 CC 在最后)

让我试着给你一些可能的组合示例:

17 00 00 00 A4 EA DB 13 02 00 00 00 00 00 00 A3 D3 02

17 00 00 00 A4 EA DB 13 02 00 00 00 00 00 00 A3 D3

17 00 00 00 A4 EA DB 13 02 00 00 00 00 00 00 A3

一直到 17 00 00 00

17 A3 D3 02 CC

17 00 A3 D3 02 CC

00 A3 D3 02 CC

17 A4 02 CC

查看字节保持相同的顺序,例如第一个字节 17 只能在第一个字节的位置

我不想要这样的组合

A4 17 02 CC

因为现在17A4 相比改变了顺序

【问题讨论】:

  • “组合”是什么意思?例如,如果您有 3 个字节,那么组合是否会是 ''(空)、'1'、'2'、'3'、'12'、'13'、'23'、'123'?或者它们是否也需要被置换,以便“12”和“21”会有所不同? (正确地,术语“组合”意味着顺序无关紧要。)
  • 如果是 1 2 3 那么组合就是 1 2 3 | 1 3 2 | 1 2 | 1 3 |等
  • 如果你不知道如何从字节数组中计算,为什么还要提到“答案”?
  • 我不明白提供的“答案”。您是否希望计算满足您的规则的组合数量?枚举所有满足您的规则的组合?或者只是找到满足您规则的任何组合?
  • @Jonathan:“我完全理解我的问题,我的麻烦在于打字。”也许。通常,写出来的问题是您大部分了解问题所在。很少有人完全了解问题但仍然无法描述它。但是,请继续尝试澄清它。花在澄清答案上的时间越多,你就越接近完全理解它。不要浪费时间添加 cmets —— 那是令人困惑和无效的。相反,花时间解决问题以使其正确。

标签: vb.net byte combinations


【解决方案1】:

正如其他人所提到的,基本思想是使用 19 位的位掩码,并为每个数字计算应包含原始列表中的哪些字节。

这是一个打印所有 2^19 可能性的 C# 程序。和以前一样,它不考虑重复:

namespace ConsoleApplication2 {
    using System;

    class Program {
        private static int[] sourceBytes = { 0x17, 0x00, 0x00, 0x00, 0xA4, 0xEA, 0xDB, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xD3, 0x02, 0xCC };

        private static bool IsBitSet(int n, int bit) {
            int mask = 1 << bit;
            return ((n & mask) == mask);
        }

        private static int NumberOfBits(int n) {
            int sum = 0;
            while (n > 0) {
                if ((n & 1) == 1) {
                    sum++;
                }
                n >>= 1;
            }
            return sum;
        }

        static void Main(string[] args) {
            for (int i = 524288 - 1; i >= 0; i--) { // 524,288 = 2^19
                if (NumberOfBits(i) >= 4) {
                    // Add the bytes from the list that are in the current bit mask
                    for (int bit = 0; bit < sourceBytes.Length; bit++) {
                        if (IsBitSet(i, bit)) {
                            Console.Write(sourceBytes[bit]);
                            Console.Write(' ');
                        }
                    }
                    Console.WriteLine();
                }
            }
        }
    }
}

【讨论】:

  • 不,你真的不想要它们。如果你真的想要他们,你就会把你的生命奉献给其他任何事情。你仍然永远不会得到它们。他们比口袋妖怪更糟糕。
  • 你可以想要,但你不能拥有。计算量太大。
  • (23 选择 9) * 14! =约2 55。还是 (24!) / (9!) = 260。还是太多了。
  • 嗯...你们有谁读过代码吗?这里只有 524,288 种组合。非常可行……
  • @Chip - 一开始的问题有点不同。我和其他人的 cmets 是关于原始问题的。
【解决方案2】:

我想这就是你要找的东西:

Module Module1

    Sub Main()
        Dim bytes() As Byte = {&H17, &H0, &H0, &H0, &HA4, &HEA, &HDB, &H13, &H2, &H0, &H0, &H0, &H0, &H0, &H0, &HA3, &HD3, &H2, &HCC}

        Combine(New Byte() {}, bytes)
    End Sub

    Sub Combine(ByVal sequence() As Byte, ByVal pool() As Byte)
        '   test current sequence
        If Test(sequence) Then
            Console.Write("Found sequence: ")
            For Each b As Byte In sequence
                Console.Write("{0:X2} ", b)
            Next
            Console.WriteLine()
        End If

        '   done if pool is empty
        If pool.Length = 0 Then
            Return
        End If

        '   recurse adding next byte from the pool
        Dim newSequence(sequence.Length) As Byte
        Array.Copy(sequence, newSequence, sequence.Length)
        newSequence(sequence.Length) = pool(0)
        Dim newPool(pool.Length - 2) As Byte
        Array.Copy(pool, 1, newPool, 0, pool.Length - 1)
        Combine(newSequence, newPool)

        '   recurse without adding next byte from the pool
        Combine(sequence, newPool)
    End Sub

    Function Test(ByVal sequence() As Byte) As Boolean
        '   the test function that you haven't provided goes here

        '   this example returns True if the sequence is 4 bytes or more, causing every combination of at least 4 bytes to be printed
        If (sequence.Length >= 4) Then
            Test = True
        Else
            Test = False
        End If
    End Function

End Module

我将 Test 函数的实现留给您,因为您没有在原始问题中提供。我的实现基本上将所有 4 字节或更多字节的序列视为通过测试,因此它会打印所有组合。

我使用了一种递归算法,该算法以一个空序列和一个字节“池”中的所有 19 个字节开始。然后我通过将池的第一个字节移动到我正在构建的序列中进行递归,然后完全忽略池的第一个字节。

【讨论】:

    【解决方案3】:

    我想我终于明白了这个问题:

    你有 19 种物品,你想知道如果你拿了你能做出多少组合

    • 一次 4 个
    • 一次 5 个
    • ...
    • 一次 19 个。

    n 项的组合数 m 一次被称为 "n 选择 m " 并计算为:

                 n
    ——————
    (m !) (n - m) !

    所以你需要为 m 从 4 到 19 的所有值添加(19 选择 m)。

    您可以通过以下方式简化计算:

         n 选择 m   =   n 选择 (n - m)

    所以您可以计算从 m = 4 到 m = 9 的组合,将其加倍以说明 m = 10 到 m = 15,然后添加 m = 15 到 19 的组合。

    这是一个用于计算的 bash shell 脚本,在大约四分之一秒的计算后给出 523128 的答案:

    # Calculate the factorial of $1.
    fact()
    {
        local f=1
        local i
    
        for ((i=1; i<=$1; ++i)); do f=$((f*i)); done
        echo $f
    }
    
    # Calculate the combinations of $1 choose $2
    comb()
    {
        local c;
        local fn=$(fact $1)
        local fm=$(fact $2)
        local fnm=$(fact $(($1-$2)))
    
        echo $((fn / fm / fnm))
    }
    
    # Sum the combinations of 19 choose m, as m = 4 .. 19.
    n=19
    sum=0
    for ((m=4; m<=n; m++)); do
         sum=$((sum + $(comb $n $m)));
    done
    
    echo $sum
    
    #EOF
    

    当然,您必须手动删除重复项。 :-)

    【讨论】:

      【解决方案4】:

      基本上,您要求的是长度为 (23*8) == 184 位的二进制数。我相信这样的数字比宇宙中的原子还要多!组合数为 2 ** (23 * 8)。

      要思考为什么会这样,只需意识到这是一个简单的彩票,其中允许数字重复。您为第一个字节选择一个数字,该数字可以在 0 到 255 之间(256 个选项)。然后你为第二个字节选择一个数字,它可以在 0 到 255 之间,所以你有 (256 * 256) 选项。然后你为第三个字节选择一个数字,它可以在 0 到 255 之间,所以你有 (256 * 256 * 256) 个选项(此时为 1600 万,还有 20 个字节......)

      您还允许使用更短的数字这一事实确实增加了 2 ** 184 个可能的字节排列数量,但不足以显着改变问题的易处理性。

      【讨论】:

      • 我已经对问题进行了相当大的更改,这应该使可能性的数量更小,但它是否足够小以至于可行?
      • 你应该解释你的数字 23 和 8 是从哪里得到的。我看不出它们在原始问题中的位置。 (问题可能已经改变。)
      • 问题确实发生了变化,所以请不要对这个答案投反对票
      【解决方案5】:

      问题中最重要的部分是字节顺序不能改变

      让我们从第一个简化的问题开始:

      1. 假设每个数字都是不同的。 (显然是错误的)
      2. 假设你对选择的数量没有下限(显然也是错误的)

      那么你对每个数字都有一个简单的选择:我应该包括这个数字吗? (顺序已经给出。)对于这个简化的问题,您只有 219=524288 种可能性。这需要一段时间才能打印出来,但它足够小,可以计算。

      删除任何一个简化都会让您有更少的可能性。

      所以,让我们删除第一个简化。当您查看一个唯一号码时,您有两种选择:要么将该号码放入您的组合中,要么将其排除在外。当您查看 n 个 00 序列时,您有 n+1 个选择:不将 00 放入组合中,将一个 00 放入组合中,...,将 n 00s 放入组合中。

      因此,此时您有 2 * 4 * 25 * 7 * 24 = 28672 个选项。

      我留给你算出这些选择中有多少只有 3 个字节或更少。

      【讨论】:

        猜你喜欢
        • 2013-10-06
        • 2015-04-13
        • 2023-03-18
        • 2014-09-24
        • 2013-04-19
        • 1970-01-01
        • 1970-01-01
        • 2023-04-11
        • 1970-01-01
        相关资源
        最近更新 更多