1049 命题逻辑(java)— 离散数学应用(详解)
2018-02-22 23:37
351 查看
问题描述
在命题逻辑中,每个变元可以取值为真或假,通过逻辑运算符连接得到逻辑表达式,逻辑表达式的值由逻辑变元的值计算得出。
以下是常用的逻辑运算符。
~:表示否定,~P为真当且仅当P为假。
>:蕴含,P>Q为真当且仅当Q为真或者P为假。
^:合取,P^Q为真当且仅当P和Q同为真。
v:析取,PvQ为真当且仅当P和Q中至少一个为真。
重言式是指无论变元如何取值其结果都为真的表达式,矛盾式是指无论变元如何取值其结果都为假的表达式。
在表式逻辑表达式的时候,可以使用辅助符号来方便描述,一个辅助符号可能是另外两个变元或辅助符号运算的结果。
为了使用辅助符号来表示否定运算,我们设置一个虚拟的辅助符号X0,使用X0和另一个变元运算P运算后即得到~P的结果。
给定一系列辅助符号的定义,问最后一个辅助符号是重言式、矛盾式还是其他表达式。
输入格式
输入数据第一行是两个整数n、m(1<=n<=4,1<=m<=10)。表示在输入中出现的变元不超过n个、辅助符号为m个,变元依次为P0, P1, ..., Pn-1,辅助符号依次为A0, A1, ..., Am-1。
从第二行开始,依次描述A0,A1,…Am-1,并严格依照以下格式:
Ai L ? R
其中Ai依次为A0, A1, ..., Am-1。?可以为“~”、“>”、“^”、“v”。L和R可以是变元或者之前出现过的辅助符号。
若?为“~”,则L必定为X0。
输出格式
若Am-1为重言式,输出1。
若Am-1为矛盾式,输出-1。
若两者都不是,输出0。
样例输入
1 2
A0 X0 ~ P0
A1 A0 v P0
样例输出
1
题目分析:
离散数学中关于命题逻辑的应用
算法分析:
将左项 left[ ] 和右项 right[ ] 分开,根据题意写逻辑判断。
为了具体化地分析,先用样例数据做说明。输入数据第一行是两个整数1、2。表示在输入中出现的变元不超过1个,此处为P0;辅助符号为2个,此处为A0,A1。
首先我们引入二维数组value[ ][ ] 记录真假,result[ ] [ ]记录结果。赋初值value[0][0]为假(0),value[1][0]为真(1)。
在输入第一行后,根据题意X0为虚拟的辅助符号,那么只记录右项P0,并将value[0][0]的值(0)赋给right[0],value[1][0]的值(1)赋给right[1],这里逻辑运算符为否定运算符,由题意,若右项right[0]为真,则result[0][0]为假,同理若right[1]为真,则result[1][0]为假。此处right[0]=0,result[0][0]=1;right[1]=1,result[1][0]=0。
接着输入第二行,记录左项A0,因为A0就是根据第一行的输入做出的逻辑判断,所以将result[0][0]的值(1)赋给left[0],result[1][0]的值(0)赋给left[1]。再按照输入第一行时记录右项的方式记录此处P0(实际上是一样的记录方式,不改变right[],即right[0]仍为0,right[1]仍为1,因为这里的变元仍然是P0),这里逻辑运算符为析取运算符,由题意,左项和右项中至少有一个为真,则为真,即A1,也就是result[0][1]=1,result[1][1]=1。
上述我们已经记录了A1的可能结果,也就是最后一个辅助符号的可能结果,根据题意需要判断A1是重言式还是矛盾式,既然我们已经得到result[0][1]=1,result[1][1]=1,也就是说无论变元怎么取值,结果总为真,那么A1显然是重言式,输出1。
下面我们往一般化去考虑,如果有多个变元呢,这也就是将value引为二维数组,而不是一维数组的原因。根据上述已知,当只有一个变元P0时,我们赋初值value[0][0]为假(0),value[1][0]为真(1),因为一个变元的真假情况只可能有这两种,也就是2的1次方,当有n变元时,情况数自然扩大为2的n次方。
同时这里涉及到一个排列组合问题,每一个变元的值可以取真(1)或假(0),n个变元组合可能有哪些情况。比如说有3个变元,就有000,100,010,110,001,101,011,111八种情况,详细来说也就是我们将value赋值为了:
value[0][0]=0,value[0][1]=0,value[0][2]=0
value[1][0]=1,value[1][1]=0,value[1][2]=0
value[2][0]=0,value[2][1]=1,value[2][2]=0
value[3][0]=1,value[3][1]=1,value[3][2]=0
value[4][0]=0,value[4][1]=0,value[4][2]=1
value[5][0]=1,value[5][1]=0,value[5][2]=1
value[6][0]=0,value[6][1]=1,value[6][2]=1
value[7][0]=1,value[7][1]=1,value[7][2]=1
接下来根据一开始我们对样例数据的分析过程,可以归纳得知,我们对这每一个组合按照先后顺序求出了A0,A1...An的可能结果,同样以n=3为例,也就是得到了A7的可能结果,如果每一种可能结果都为真(1),也就是重言式了,输出1;同理,如果每一种可能结果都为假(0),也就是矛盾式,输出-1;否则输出0。
这就是这道题的整个思路。最后在代码中对细节进行完善和优化即可。
算法设计:import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int probability = 1; //可能的情况数
for (int i = 0; i < n; i++) {
probability *= 2;
}
int result[][] = new int[probability][m+1]; //记录结果
int value[][] = new int[probability][n+1]; //记录真假
for (int i = 0; i < probability; i++) {
int k = i;
for (int j = 0; j < n; j++) {
value[i][j] = k % 2;
k /= 2;
}
}
int []right = new int[probability]; //记录右项
int []left = new int[probability]; //记录左项
String temp = sc.nextLine(); //读取多余的换行符
for (int i = 0; i < m; i++) {
String data = sc.nextLine();
for (int j = 0; j < probability; j++) {
if (data.charAt(3) == 'P')
left[j] = value[j][(int) data.charAt(4) - '0'];
else if (data.charAt(3) == 'A')
left[j] = result[j][(int) data.charAt(4) - '0'];
if (data.charAt(8) == 'P')
right[j] = value[j][(int) data.charAt(9) - '0'];
else if (data.charAt(8) == 'A')
right[j] = result[j][(int) data.charAt(9) - '0'];
switch (data.charAt(6)) { //逻辑运算符判断
case '~':
if (right[j] == 1)
result[j][i] = 0;
else
result[j][i] = 1;
break;
case '>':
if (right[j] == 1 || left[j] == 0)
result[j][i] = 1;
else
result[j][i] = 0;
break;
case '^':
if (right[j] == 1 && left[j] == 1)
result[j][i] = 1;
else
result[j][i] = 0;
break;
case 'v':
if (right[j] == 1 || left[j] == 1)
result[j][i] = 1;
else
result[j][i] = 0;
break;
default:
break;
}
}
}
int sum = 0;
for (int i = 0; i < probability; i++) {
sum += result[i][m - 1];
}
if (sum == 0) {
System.out.println(-1);
} else if (sum == probability) {
System.out.println(1);
} else {
System.out.println(0);
}
}
}
在命题逻辑中,每个变元可以取值为真或假,通过逻辑运算符连接得到逻辑表达式,逻辑表达式的值由逻辑变元的值计算得出。
以下是常用的逻辑运算符。
~:表示否定,~P为真当且仅当P为假。
>:蕴含,P>Q为真当且仅当Q为真或者P为假。
^:合取,P^Q为真当且仅当P和Q同为真。
v:析取,PvQ为真当且仅当P和Q中至少一个为真。
重言式是指无论变元如何取值其结果都为真的表达式,矛盾式是指无论变元如何取值其结果都为假的表达式。
在表式逻辑表达式的时候,可以使用辅助符号来方便描述,一个辅助符号可能是另外两个变元或辅助符号运算的结果。
为了使用辅助符号来表示否定运算,我们设置一个虚拟的辅助符号X0,使用X0和另一个变元运算P运算后即得到~P的结果。
给定一系列辅助符号的定义,问最后一个辅助符号是重言式、矛盾式还是其他表达式。
输入格式
输入数据第一行是两个整数n、m(1<=n<=4,1<=m<=10)。表示在输入中出现的变元不超过n个、辅助符号为m个,变元依次为P0, P1, ..., Pn-1,辅助符号依次为A0, A1, ..., Am-1。
从第二行开始,依次描述A0,A1,…Am-1,并严格依照以下格式:
Ai L ? R
其中Ai依次为A0, A1, ..., Am-1。?可以为“~”、“>”、“^”、“v”。L和R可以是变元或者之前出现过的辅助符号。
若?为“~”,则L必定为X0。
输出格式
若Am-1为重言式,输出1。
若Am-1为矛盾式,输出-1。
若两者都不是,输出0。
样例输入
1 2
A0 X0 ~ P0
A1 A0 v P0
样例输出
1
题目分析:
离散数学中关于命题逻辑的应用
算法分析:
将左项 left[ ] 和右项 right[ ] 分开,根据题意写逻辑判断。
为了具体化地分析,先用样例数据做说明。输入数据第一行是两个整数1、2。表示在输入中出现的变元不超过1个,此处为P0;辅助符号为2个,此处为A0,A1。
首先我们引入二维数组value[ ][ ] 记录真假,result[ ] [ ]记录结果。赋初值value[0][0]为假(0),value[1][0]为真(1)。
在输入第一行后,根据题意X0为虚拟的辅助符号,那么只记录右项P0,并将value[0][0]的值(0)赋给right[0],value[1][0]的值(1)赋给right[1],这里逻辑运算符为否定运算符,由题意,若右项right[0]为真,则result[0][0]为假,同理若right[1]为真,则result[1][0]为假。此处right[0]=0,result[0][0]=1;right[1]=1,result[1][0]=0。
接着输入第二行,记录左项A0,因为A0就是根据第一行的输入做出的逻辑判断,所以将result[0][0]的值(1)赋给left[0],result[1][0]的值(0)赋给left[1]。再按照输入第一行时记录右项的方式记录此处P0(实际上是一样的记录方式,不改变right[],即right[0]仍为0,right[1]仍为1,因为这里的变元仍然是P0),这里逻辑运算符为析取运算符,由题意,左项和右项中至少有一个为真,则为真,即A1,也就是result[0][1]=1,result[1][1]=1。
上述我们已经记录了A1的可能结果,也就是最后一个辅助符号的可能结果,根据题意需要判断A1是重言式还是矛盾式,既然我们已经得到result[0][1]=1,result[1][1]=1,也就是说无论变元怎么取值,结果总为真,那么A1显然是重言式,输出1。
下面我们往一般化去考虑,如果有多个变元呢,这也就是将value引为二维数组,而不是一维数组的原因。根据上述已知,当只有一个变元P0时,我们赋初值value[0][0]为假(0),value[1][0]为真(1),因为一个变元的真假情况只可能有这两种,也就是2的1次方,当有n变元时,情况数自然扩大为2的n次方。
同时这里涉及到一个排列组合问题,每一个变元的值可以取真(1)或假(0),n个变元组合可能有哪些情况。比如说有3个变元,就有000,100,010,110,001,101,011,111八种情况,详细来说也就是我们将value赋值为了:
value[0][0]=0,value[0][1]=0,value[0][2]=0
value[1][0]=1,value[1][1]=0,value[1][2]=0
value[2][0]=0,value[2][1]=1,value[2][2]=0
value[3][0]=1,value[3][1]=1,value[3][2]=0
value[4][0]=0,value[4][1]=0,value[4][2]=1
value[5][0]=1,value[5][1]=0,value[5][2]=1
value[6][0]=0,value[6][1]=1,value[6][2]=1
value[7][0]=1,value[7][1]=1,value[7][2]=1
接下来根据一开始我们对样例数据的分析过程,可以归纳得知,我们对这每一个组合按照先后顺序求出了A0,A1...An的可能结果,同样以n=3为例,也就是得到了A7的可能结果,如果每一种可能结果都为真(1),也就是重言式了,输出1;同理,如果每一种可能结果都为假(0),也就是矛盾式,输出-1;否则输出0。
这就是这道题的整个思路。最后在代码中对细节进行完善和优化即可。
算法设计:import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int probability = 1; //可能的情况数
for (int i = 0; i < n; i++) {
probability *= 2;
}
int result[][] = new int[probability][m+1]; //记录结果
int value[][] = new int[probability][n+1]; //记录真假
for (int i = 0; i < probability; i++) {
int k = i;
for (int j = 0; j < n; j++) {
value[i][j] = k % 2;
k /= 2;
}
}
int []right = new int[probability]; //记录右项
int []left = new int[probability]; //记录左项
String temp = sc.nextLine(); //读取多余的换行符
for (int i = 0; i < m; i++) {
String data = sc.nextLine();
for (int j = 0; j < probability; j++) {
if (data.charAt(3) == 'P')
left[j] = value[j][(int) data.charAt(4) - '0'];
else if (data.charAt(3) == 'A')
left[j] = result[j][(int) data.charAt(4) - '0'];
if (data.charAt(8) == 'P')
right[j] = value[j][(int) data.charAt(9) - '0'];
else if (data.charAt(8) == 'A')
right[j] = result[j][(int) data.charAt(9) - '0'];
switch (data.charAt(6)) { //逻辑运算符判断
case '~':
if (right[j] == 1)
result[j][i] = 0;
else
result[j][i] = 1;
break;
case '>':
if (right[j] == 1 || left[j] == 0)
result[j][i] = 1;
else
result[j][i] = 0;
break;
case '^':
if (right[j] == 1 && left[j] == 1)
result[j][i] = 1;
else
result[j][i] = 0;
break;
case 'v':
if (right[j] == 1 || left[j] == 1)
result[j][i] = 1;
else
result[j][i] = 0;
break;
default:
break;
}
}
}
int sum = 0;
for (int i = 0; i < probability; i++) {
sum += result[i][m - 1];
}
if (sum == 0) {
System.out.println(-1);
} else if (sum == probability) {
System.out.println(1);
} else {
System.out.println(0);
}
}
}
相关文章推荐
- Java应用技巧:对于 Cookie 的操作详解
- 离散数学 第一章 命题逻辑 1-1 命题及其表示法
- java.util.Scanner应用详解
- Java正则表达式应用详解(1)
- java中的内部类详解和应用
- Java正则表达式应用详解(2)
- Java应用技巧:对于 Cookie 的操作详解
- 自定义ClassLoader实现java应用核心逻辑模块热部署
- java.util.Scanner应用详解 转
- Java正则表达式应用详解
- 离散数学及其应用--第一章-命题逻辑的基本概念
- java.util.Scanner应用详解
- [java] eclipse+ADT 进行android应用签名详解
- Java应用技巧:Cookie 的操作详解
- 离散数学 第一章 命题逻辑 1-3命题公式与翻译
- Java环境下Memcached应用详解
- java.util.Scanner应用详解
- Android JNI 使用的数据结构JNINativeMethod详解 ||建立Android SDK下的JNI、JAVA应用完整步骤---Android JAVA调用C++代码
- Java应用技巧:对于 Cookie 的操作详解
- 高级应用JAVA多线程详解(二)