测试3个中的4个是否为真的逻辑

165

如果且仅当4个布尔值中有3个为真时,我想返回True

我得到的最接近的结果是(x ^ y) ^ (a ^ b):

我该怎么办?


10
嗯,我能想到的唯一方法是使用计数,好问题! :) - I am Cavic
10
你的想法并不错,但你需要注意否定:当只有一个否定值为真时,not a ^ not b ^ not c ^ not d 才为真。这意味着,在原来的值中,恰好有一个是假的。 - Ingo
23
你在这些细节背后的实际问题是什么? - Wolf
5
当只有一个是假的并且其中三个是假的时,如果@Ingo不是a、不是b、不是c、也不是d,则返回true。 - NameSpace
10
明显的非计数解决方案是 (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d) - Jason C
显示剩余9条评论
27个回答

11
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

第一个表达式搜索4个中的1或3个true。第二个表达式消除4个中的0或1(有时是2)true


11

Java 8,过滤掉错误的值,并计数剩余的正确值:

public static long count(Boolean... values) {
    return Arrays.stream(values).filter(t -> t).count();
}

那么你可以按如下方式使用它:
if (3 == count(a, b, c, d)) {
    System.out.println("There... are... THREE... lights!");
}

轻松推广到检查 m 个项目中的 n 个是否为真。


10

以下是使用C#和LINQ的解决方法:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;

10

那就是对称布尔函数S₃(4)。对称布尔函数是一种仅取决于输入设置数量而不取决于其输入的布尔函数。Knuth在计算机程序设计艺术第4卷第7.1.2节中提到了这种类型的函数。

S₃(4)可以通过以下方式使用7个操作来计算:

(x && y && (a || b)) ^ ((x || y) && a && b)

Knuth指出这是最优的,这意味着您不能使用常规运算符进行少于7次操作: &&, || , ^, <,>

然而,如果您想在使用1表示真和0表示假的语言中使用它,您也可以轻松使用加法:

x + y + a + b == 3

这使得你的意图非常明确。


9
(a && b && (c xor d)) || (c && d && (a xor b))

从纯逻辑角度来看,我得出了以下结论。

根据抽屉原理,如果恰好有三个命题为真,则要么 a 和 b 为真,要么 c 和 d 为真。接下来只需要将这些情况中的每一种与另外两个命题之一相 “与” 即可。

Wolfram 真值表


这相当于NameSpace的第二个解决方案。 - Brilliand
@Brilliand 对我来说似乎有所不同。他将所有的异或操作组合在一起,得到所有的3或1,然后通过要求至少来自2个不同组中的一个来排除1的情况。(总结为1或3以及至少2个)。我的方法则需要从其中一个不同组中都选取两个,然后再从另一个组中恰好选取一个。 - Cruncher
如果你的意思是 mine <=> his 的等价,那么我不知道该说什么,因为这是可以预料的。 - Cruncher
我想我的意思是,这个答案与NameSpace的第二个解决方案完全相同,没有添加任何NameSpace(早期)答案未涵盖的新内容。不过,无论如何我会点赞的。 - Brilliand

8
如果您使用类似Karnaugh Maps的逻辑可视化工具,您会发现这是一个问题,如果您想在一行中写出它,那么您无法避免完整的逻辑项。Lopina已经展示了它,这是不可能更简单的。您可以因子化一点,但对于您和机器来说,它仍然很难读懂。
计数解决方案并不坏,它们显示您真正需要的内容。如何高效地计数取决于您的编程语言。使用Python或LinQ的数组解决方案很好看,但要注意,这很慢。Wolf的(a+b+x+y)==3将运行得很好且快速,但前提是您的语言将“true”等同于1。如果“true”的表示为-1,则必须测试-3 :)
如果您的语言使用真布尔值,可以尝试明确编程(我使用!=作为XOR测试):
if (a)
{
    if (b)
        return (x != y);    // a,b=true, so either x or y must be true
    else
        return (x && y);     // a=true, b=false, so x AND y must be true
}
else
{
    if (b)
        return (x && y);    // a=false, b=true, so x and y must be true
    else
        return false;       // a,b false, can't get 3 of 4
}

"x != y"仅在x和y是布尔类型时才适用。如果它们是其他类型,其中0为false,而其他任何值均为true,这可能会失败。那么使用布尔异或,或者( (bool)x!=(bool)y ),或者编写“if (x) return (y==false) else return (y==true);”,这对计算机来说需要更多的工作。

如果您的编程语言提供三元运算符?:,您可以将其缩短为

if (a)
    return b ? (x != y) : (x && y);
else
    return b ? (x && y) : false;

可以稍微保留一些可读性,或者大幅简化它以...

return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);

这段代码进行了三次逻辑测试(a的状态、b的状态、x和y的比较),应该比这里其他答案更快。但是你需要加上注释,否则三个月后你可能无法理解它 :)


8

这里有很多好的答案;以下是其他人尚未发布的一种替代表述:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)

谢谢您的回答,但是您能否加上一些关于它如何工作的评论呢?谢谢。 - Deanna
很抱歉要挑战你,这是我被安排的审核任务。不过至少我通过了。。:) - Deanna

7

与第一个答案类似,但是纯Java实现:

int t(boolean b) {
    return (b) ? 1 : 0;
}

if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

我更喜欢将它们视为整数,因为这样可以使代码更易读。


7
在Python中,要查看可迭代元素中有多少个为True,请使用sum(它很简单):
设置:
import itertools

arrays = list(itertools.product(*[[True, False]]*4))

实际测试

for array in arrays:
    print(array, sum(array)==3)

输出

(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False

5
如果你需要非编程解决方案,那么K-map和Quine-McCluskey算法是你需要的,它们可以帮助你最小化布尔函数。
在你的情况下,结果为:
y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

如果您想以编程方式实现此目标,需要处理可变数量的变量以及自定义的“阈值”,则通过迭代布尔值列表并计算“true”出现次数是非常简单和直接的。


1
横杠上方的符号代表什么?我注意到它正在列表中向下移动。 - NameSpace
3
@NameSpace 是人们用来表示“不”的太多符号之一,需要翻译成中文。 - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接