【问题标题】:generate a truth table given an input?给定输入生成真值表?
【发布时间】:2011-03-31 02:21:22
【问题描述】:

有没有一种智能算法,可以在多维数组或容器中获取多个概率并生成对应的真值表

例如:

n = 3
N : [0 0 0
     0 0 1
     0 1 0 
     ...
     1 1 1] 

我可以使用 for 循环和 Ifs 来做到这一点,但我知道我的方法会很慢而且很耗时。所以,我问是否有一个高级功能可以用来尽可能高效地做到这一点?

【问题讨论】:

  • 我认为“概率”在这里是错误的词。概率不是整数。

标签: c++ logic


【解决方案1】:

如果允许我们在开始时用全零填充表格,那么应该可以准确地执行2^n - 1 填充来设置我们想要的 1 位。不过,这可能并不比编写手动循环快,它完全没有配置文件。

编辑: std::vector<std::vector<int> > output(n, std::vector<int>(1 << n)); 行声明了一个向量的向量。外部向量的长度为 n,内部向量为 2^n(n 个输入的真值结果的数量),但我使用左移进行幂计算,因此编译器可以插入一个常量而不是调用,例如, pow。在n=3 的情况下,我们最终得到一个 3x8 向量。我以这种方式组织它(而不是通常的 8x3 以行作为第一个索引),因为我们将在输出数据中利用基于列的模式。以这种方式使用 vector 构造函数还可以确保向量的向量的每个元素都初始化为 0。因此我们只需要担心将我们想要的值设置为 1,剩下的就不用管了。

第二组嵌套的for 循环只是用来在完成后打印出结果数据,没什么特别的。

第一组 for 循环实现了真正的算法。我们在此处的输出数据中利用了基于列的模式。对于给定的真值表,最左边的列将有两个部分:前半部分全为 0,后半部分全为 1。由于我们预先填充了零,因此将应用从一半开始的半列高度的单次填充我们需要的所有1。第二列将有 1/4th 0、1/4th 1、1/4th 0、1/4th 1 行。因此,两个填充将应用我们需要的所有 1。我们重复这个直到我们到达最右边的列,在这种情况下,每隔一行都是 0 或 1。

我们开始说“我需要一次填充一半的行”(unsigned num_to_fill = 1U << (n - 1);)。然后我们遍历每一列。第一列从要填充的位置开始,用 1 填充那么多行。然后我们增加行并将填充大小减少一半(现在我们一次填充 1/4 的行,但是我们跳过空白行并再次填充)用于下一列。

例如:

#include <iostream>
#include <vector>

int main()
{
    const unsigned n = 3;
    std::vector<std::vector<int> > output(n, std::vector<int>(1 << n));

    unsigned num_to_fill = 1U << (n - 1);
    for(unsigned col = 0; col < n; ++col, num_to_fill >>= 1U)
    {
        for(unsigned row = num_to_fill; row < (1U << n); row += (num_to_fill * 2))
        {
            std::fill_n(&output[col][row], num_to_fill, 1);
        }
    }

    // These loops just print out the results, nothing more.
    for(unsigned x = 0; x < (1 << n); ++x)
    {
        for(unsigned y = 0; y < n; ++y)
        {
            std::cout << output[y][x] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

【讨论】:

  • 这行得通,但我不明白。这一行 std::vector<:vector> > output(n, std::vector(1
  • 我编辑了这个以使用无符号变量,其中移位可能是一个问题。这也不适用于适当数量的输入位。
  • 使用您当前的算法来填充位,当它是一维向量并且向量中的数据存储为主要列时,您将如何计算索引值?
【解决方案2】:

您可以通过注意矩阵中的每一行表示一个 n 位二进制数,将他的问题分成两部分,其中 n 是概率的数量[原文如此]。

所以你需要:

  • 遍历所有 n 位数字
  • 将每个数字转换为二维容器的一行

编辑:

如果您只担心运行时间,那么对于常量 n,您总是可以预先计算表格,但它认为您在计算时会遇到 O(2^n) 复杂度

【讨论】:

    【解决方案3】:

    你想用二进制数字系统写从 0 到 2^N - 1 的数字。它没有什么聪明之处。您只需要填充二维数组的每个单元格。你不能比这更快。

    您可以在不直接迭代数字的情况下做到这一点。请注意,最右边的列重复0 1,然后下一列重复0 0 1 1,然后是下一列0 0 0 0 1 1 1 1,依此类推。每列都在重复 2^columnIndex(从 0 开始)零,然后是一。

    【讨论】:

    • 好吧,我知道,但我认为有更快的方法。
    【解决方案4】:

    要详细说明 jk 的答案... 如果你有 n 个布尔值(“概率”?),那么你需要

    • 创建一个 n × 2^n 的真值表数组
    • 循环 i 从 0 到 (2^n-1)
    • 在该循环内,将 j 从 0 循环到 n-1
    • 在那个循环中,设置真值表[i][j] = i 的第 j 位(例如 (i >> j) & 1)

    【讨论】:

    • 我认为应该是&amp; 1
    • 我不明白,不是 i, j 应该是整数吗?右移将如何与他们合作?
    • @Mark B,你是对的。将编辑它。 @Ahmed,我不明白你在暗示什么问题。你是说&gt;&gt; 的左操作数还是右操作数不能是int?我在这里假设 c++,基于标签。
    • 我只是没有得到这条线 truthTable[i][j] = i 的第 j 位(例如 (i >> j) & 1) 例如 t[1][3] = 3rd一点点 1 ???这有什么意义?
    • @Ahmed,我使用 table[row][col] 而不是 table[col][row] 可能会让人感到困惑。假设 n = 3。 i 从 0 到 7,代表示例中的 8 行。 j 从 0 到 2,代表 3 列。每当 i > 2) 将以零结尾,因此 t[i][2] = 0。这对应于示例中前三行开头的零。
    【解决方案5】:

    卡诺图或 Quine-McCluskey

    http://en.wikipedia.org/wiki/Karnaugh_map http://en.wikipedia.org/wiki/Quine%E2%80%93McCluskey_algorithm

    这应该会引导您朝着最小化结果真值表的正确方向前进。

    【讨论】:

    • 我不想最小化它,只是为了创建它。
    • 抱歉 - 阅读问题太快 - 误解了您的目标。
    猜你喜欢
    • 1970-01-01
    • 2021-11-24
    • 2016-03-22
    • 2011-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-01
    相关资源
    最近更新 更多