[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

不限语言解决“谁做了糗事儿”问题

本帖最后由 老刘1号 于 2020-2-26 21:04 编辑
4人中有1人做了糗事儿,已知有3人说了真话、1人说了谎话。
a说:不是我;
b说:是c;
c说:是d;
d说:c瞎说。
请判断是谁做了糗事儿?

附一个C,无脑排除法:https://tool.lu/coderunner/embed/7Xm.html

烧脑................
设真话 =1 ; a=b=c=d=1; 假话为 -1;
a说不是我  a=1;
b说是c      c=1+(-1)=0;
c说是d      d=1+(-1)=0;
d说c瞎说   c=0+(-1)=-1;
所以 C 说谎。??
纯推理。
QQ: 己阵亡
脚本优先 [PowerShell win10]

TOP

c说:是d;
d说:c瞎说。
这上二者矛盾, 必一真一假, 故下二者必皆真(已知有3人说了真话、1人说了谎话)
a说:不是我;
b说:是c;
故 c 做了糗事儿

TOP

本帖最后由 red2020 于 2020-2-27 02:37 编辑

过于简单,不超过20行搞定
  1. #include <stdio.h>
  2. int main ()
  3. {
  4. unsigned char matrix[128];
  5. matrix['a'] = 0x07; //二进制 0111 ,a说不是我,相当于其他人都有可能,所以除一号位其他位都标记为二进制1
  6. matrix['b'] = 0x02; //二进制 0010 ,b说是c,把三号位标记为二进制1
  7. matrix['c'] = 0x01; //二进制 0001 ,c说是d,把四号位标记为二进制1
  8. matrix['d'] = (~matrix['c'])&0x0F; //二进制 1110 ,d说c瞎说,相当c的矩阵值取反,~matrix['c']表示
  9. for(int j = 'a'; j <= 'd'; j++)
  10. {
  11. unsigned char judgeMark = 0x0F; //只取一个字节的后4位标记abcd做的状态
  12. for(int i = 'a'; i <= 'd'; i++)
  13. judgeMark &= (i == j)?~matrix[i]:matrix[i];
  14. if(judgeMark)
  15. printf("It's '%c'. :[%d,%d,%d,%d]\n", j, (judgeMark>>3)&1, (judgeMark>>2)&1, (judgeMark>>1)&1, judgeMark&1);
  16. }
  17. return 0;
  18. }
复制代码
1

评分人数

TOP

布尔代数化简算法:
设 a,b,c,d 4个基本命题分别表示4人中的同命题字母代号者做了糗事儿
由 "4人中有1人做了糗事儿" 可得
P式:
(a && !b && !c && !d) ||
(!a && b && !c && !d) ||
(!a && !b && c && !d) ||
(!a && !b && !c && d)


将4人的说法转化为基本命题布尔代数式
a说:不是我;     asay: !a
b说:是c;        bsay: c
c说:是d;        csay: d
d说:c瞎说。      dsay: !csay <==> !d

由 "有3人说了真话、1人说了谎话" 可得
Q式:
(! !a && c && d && !d) ||
(!a && !c && d && !d) ||
(!a && c && !d && !d) ||
(!a && c && d && ! !d)

P式 && Q式:
(
    (a && !b && !c && !d) ||
    (!a && b && !c && !d) ||
    (!a && !b && c && !d) ||
    (!a && !b && !c && d)
) && (
    (! !a && c && d && !d) ||
    (!a && !c && d && !d) ||
    (!a && c && !d && !d) ||
    (!a && c && d && ! !d)
)

格式化为单行排版
((a && !b && !c && !d) || (!a && b && !c && !d) || (!a && !b && c && !d) || (!a && !b && !c && d)) && ((! !a && c && d && !d) || (!a && !c && d && !d) || (!a && c && !d && !d) || (!a && c && d && ! !d))

用布尔代数工具化简(各种数学软件都有此能力),此处用一在线工具
https://www.dcode.fr/boolean-expressions-calculator

化简结果
! a && ! b && c && ! d
与分析推理结果一致
1

评分人数

TOP

回复 4# red2020


    简洁、优雅的代码, 学习了
用按位与运算巧妙的进行了类似排除法的操作
已经被排除的人(0)不会被再次被认定(0&1=0)。

lz才疏学浅,还有一个小疑惑:
我的算法中,遇到将已经排除的”做糗事的人“认定为“做糗事的人”时,会认定为矛盾直接返回
但这个算法中似乎并没有类似的举措,只要最终有人未被排除,就直接认定为该人
这样在遇到其它类似问题时,是否可能会出现因为未返回产生的增根?

TOP

回复 2# xczxczxcz


    看不懂.jpg

TOP

回复 6# 老刘1号
取反后与已带有排除矛盾的运算成分,我的就是把你的代码翻译成布尔运算。那两层for已经假设了各种情况,我的1代表的是做了事,最后经过布尔运算只有c位是1,就是说是c做的。代码布尔逻辑上等价于你的代码,因为我就是按你的逻辑翻译成位运算而已。
1

评分人数

TOP

一万年之后学了离散数学的我又回来了,5楼标准答案,

附一个列真值表求解的:
  1. @echo off
  2. for /l %%i in (0 1 0xf) do (
  3. set /a "a=%%i&1,b=(%%i>>1)&1,c=(%%i>>2)&1,d=(%%i>>3)&1"
  4. set /a "result=((a & !b & !c & !d) | (!a & b & !c & !d) | (!a & !b & c & !d) | (!a & !b & !c & d)) & ((! !a & c & d & !d) | (!a & !c & d & !d) | (!a & c & !d & !d) | (!a & c & d & ! !d))"
  5. call echo [%%a%% %%b%% %%c%% %%d%%] - %%result%%
  6. )
  7. pause
复制代码

TOP

A=0 (没有人说是他,所以是0人)
B=0 (没有人说是他,所以是0人)
C=2 (2人说是他,所以是2人)
D=1  (2人说是他,所以是2人)
设说C有1人是假话,那么第二个一定是真话,所以是C
梦依旧在,只是,心有余而力渐有不足
年年岁岁花相似,岁岁年年人不同

TOP

  1. @echo off
  2. %格式化,设为1%
  3. for %%i in (a b c d) do (set %%i=1)
  4. %A说不是A%
  5. set /a a=a-1
  6. %B说C%
  7. set /a c=c+1
  8. %C说D%
  9. set /a d=d+1
  10. %D说C%
  11. set /a c=c+1
  12. setlocal enabledelayedexpansion
  13. echo;!a!>tmp.tmp
  14. echo;!b!>>tmp.tmp
  15. echo;!c!>>tmp.tmp
  16. echo;!d!>>tmp.tmp
  17. for /f %%i in ('sort tmp.tmp') do (set xy=%%i)
  18. del tmp.tmp
  19. for %%i in (a b c d) do (if "!xy!"=="!%%i!" echo;%%i)
  20. pause
复制代码
梦依旧在,只是,心有余而力渐有不足
年年岁岁花相似,岁岁年年人不同

TOP

回复 9# 老刘1号


    啊啊啊啊,我才发现这是坟贴...
梦依旧在,只是,心有余而力渐有不足
年年岁岁花相似,岁岁年年人不同

TOP

回复 10# cmd1152


    d说c是假不代表d说是c哦

TOP

回复 13# 老刘1号


    只有一个人说谎...D如果不是说C那么B就有点矛盾了
梦依旧在,只是,心有余而力渐有不足
年年岁岁花相似,岁岁年年人不同

TOP

返回列表