离散数学 习题篇——生成主范式

给定公式中的命题变元,以及所有极小项(或极大项)的解释,可以计算出对应主范式。

在LaTeX中,公式按照这种格式:把符号串放入一对$中。

于是$P\vee \neg Q\wedge R$会显示为P∨¬Q∧R。

Word的公式编辑器也是用相同的格式。

¬符号对应于\neg。(为让输入输出更简单,注意后面有一个空格。)

∨符号对应于\vee。(为让输入输出更简单,注意后面有一个空格。)

∧符号对应于\wedge。(为让输入输出更简单,注意后面有一个空格。)

一个在线LaTeX公式编辑器:http://latex.codecogs.com/eqneditor/editor.php?mode=NEW

输入格式:
第1行为公式中出现的所有原子命题变元符号(每个符号用一个字母表示),2≤符号个数≤10

第2行为用一个空格隔开的一个数字n和一个字符c,c为M表示下面n行为其所有极大项对应的解释,c为m表示下面n行为其所有极小项对应的赋值。

接下来有n行解释,按照字典序排列。(即类似000, 001, 010, 011这样的顺序)

输出格式:

第1行:主合取范式,若不存在输出NULL。每个极小项都在最外层加一对圆括号,按照其对应解释字典序排列。

第2行:主析取范式,若不存在输出NULL。每个极大项都在最外层加一对圆括号,按其照对应解释字典序排列。

注意:每行末尾输出一个换行。

输入样例1:
PQR
3 m
000
010
101
输出样例1:
(P\vee Q\vee \neg R)\wedge (P\vee \neg Q\vee \neg R)\wedge (\neg P\vee Q\vee R)\wedge (\neg P\vee \neg Q\vee R)\wedge (\neg P\vee \neg Q\vee \neg R)
(\neg P\wedge \neg Q\wedge \neg R)\vee (\neg P\wedge Q\wedge \neg R)\vee (P\wedge \neg Q\wedge R)
输入样例2:
PQR
3 M
000
010
101
输出样例2:
(P\vee Q\vee R)\wedge (P\vee \neg Q\vee R)\wedge (\neg P\vee Q\vee \neg R)
(\neg P\wedge \neg Q\wedge R)\vee (\neg P\wedge Q\wedge R)\vee (P\wedge \neg Q\wedge \neg R)\vee (P\wedge Q\wedge \neg R)\vee (P\wedge Q\wedge R)
输入样例3:
PQ
0 m
输出样例3:
(P\vee Q)\wedge (P\vee \neg Q)\wedge (\neg P\vee Q)\wedge (\neg P\vee \neg Q)
NULL

解题思路:
主范式之类的概念就不在这里阐述了,主要就是说一下题和思路
那么这个题说告诉你输入的真值究竟极大项还是极小项的。那么就可以想一下,n个变元一共有2n个组成的可能。

比如两个变元P,Q就是( P Q PQ PQ)、( ¬ P Q \neg PQ ¬PQ)、( P ¬ Q P\neg Q P¬Q)、( ¬ P ¬ Q \neg P\neg Q ¬P¬Q)4种。 那么,指定极大项的真值表是 01 10 的时候呢,极大项就是( P ∨ ¬ Q P\vee \neg Q P¬Q)和 ¬ P ∨ Q \neg P\vee Q ¬PQ),这个时候极小项是什么呢,就是剩下的两个,也就是( P ∧ Q P\wedge Q PQ)和( ¬ P ∧ ¬ Q \neg P\wedge \neg Q ¬P¬Q) 也就是说,当我们知道了极大项以后,剩下的组合用 ∧ \wedge 组合起来就是极小项,反之亦然。

这样的话,我们把真值表看作二进制,转换位十进制就可以使用数组来存放组合,再用确定的极大极小项去确定主范式就可以了。

代码:
再来说一下代码,python可以用int()函数来直接将字符串类型的其他进制数转换为整型的十进制数:int(“字符串”, 进制数)
那么,既然有了其他进制转换为十进制,有没有十进制转其他进制呢?答案是有的,但是这里我们不用,因为转换完成的字符串是没有“0”来补位的,如果我们有4个变元,那么我们希望1转换为二进制成为(0001)2而不是(1)2
没有库函数那我们就自己写一个吧

#将数字x转化为n位二进制数
def Bin(x, n):
    s = ''
    a = 1 << (n - 1)
    for i in range(n):
        s += '1' if x & a else '0'
        a >>= 1
    return s

接下来就是初始化数组,之前说过,现在数组的下标是真值表的十进制数,将文字组合是极大项还是极小项这个属性表示出来,比如真值为0001的组合是极大项还是极小项将在xiang[1]中进行标记

这里涉及到两个问题:

  • 第一是怎么才能判断是极大项还是极小项。想一下,现在只有极大和极小两个选项,当输入的是极小项的真值时,我们就把数组定义为全是极大项,再将极小项对应的给改成极小项就行了。(这里用M表示极大项,m表示极小项)
  • 第二是数组开多大的,n个变元就有2n个组合,所以要开2n大小的数组
def first(n, c, len):
    ch = 'M'
    if c == ch:
        ch = 'm'
    xiang = [ch] * 2 ** len
    while(n):
    	#将输入的真值转化成十进制并把相应的组合标记为相应的极大或者极小项
        i = int(input(), 2)
        xiang[i] = c
        n -= 1
    return xiang

至此, 我们已经将所有的数据初始化完成,接下来就是搞定字符串并且输出

现在我们遍历一遍数组xiang,将所有的组合都变成对应的极大极小项

有点懒,没有写成函数

#big数组中存放极大项
#small数组中存放极小项
big = []
small = []
n = len(xiang)
for i in range(n):
    s = ''
    a = Bin(i, len(bianYuan))
    n1 = len(a)
    if xiang[i] == "M":
        for j in range(n1):
            if j != 0:
                s += '\\vee '
            if a[j] == "0":
                s += bianYuan[j]
            else:
                s += '\\neg ' + bianYuan[j]
        big.append(s)
    else:
        for j in range(n1):
            if j != 0:
                s += '\\wedge '
            if a[j] == '0':
                s += '\\neg ' + bianYuan[j]
            else:
                s += bianYuan[j]
        small.append(s)

最后一个步骤就是输出了,别忘了如果没有极大项或者极小项要输出个NULL

#如果没有极大项就输出NULL,极小项同
if len(big) == 0:
    print("NULL", end="")
else:
    for i in range(len(big)):
    	#如果不是第一项,那么就用\wedge 和前面的式子连起来,极小项类似
        if i != 0:
            print("\\wedge ", end='')
        print("(%s)" % big[i], end="")
print()
if len(small) == 0:
    print("NULL", end="")
else:
    for i in range(len(small)):
        if i != 0:
            print("\\vee ", end='')
        print("(%s)" % small[i], end='')

解析完毕

完整代码如下

def Bin(x, n):
    s = ''
    a = 1 << (n - 1)
    for i in range(n):
        s += '1' if x & a else '0'
        a >>= 1
    return s

def first(n, c, len):
    ch = 'M'
    if c == ch:
        ch = 'm'
    xiang = [ch] * 2 ** len
    while(n):
        i = int(input(), 2)
        xiang[i] = c
        n -= 1
    return xiang

bianYuan = list(input())
n, c = input().split()
n = int(n)
xiang = first(n, c, len(bianYuan))

big = []
small = []
n = len(xiang)
for i in range(n):
    s = ''
    a = Bin(i, len(bianYuan))
    n1 = len(a)
    if xiang[i] == "M":
        for j in range(n1):
            if j != 0:
                s += '\\vee '
            if a[j] == "0":
                s += bianYuan[j]
            else:
                s += '\\neg ' + bianYuan[j]
        big.append(s)
    else:
        for j in range(n1):
            if j != 0:
                s += '\\wedge '
            if a[j] == '0':
                s += '\\neg ' + bianYuan[j]
            else:
                s += bianYuan[j]
        small.append(s)

if len(big) == 0:
    print("NULL", end="")
else:
    for i in range(len(big)):
        if i != 0:
            print("\\wedge ", end='')
        print("(%s)" % big[i], end="")
print()
if len(small) == 0:
    print("NULL", end="")
else:
    for i in range(len(small)):
        if i != 0:
            print("\\vee ", end='')
        print("(%s)" % small[i], end='')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值