对于一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)和^(异或)五种字符组成的逻辑表达式,再给定一个结果值。现在可以对这个没有括号的表达式任意加合法的括号,返回得到能有多少种加括号的方式,可以达到这个结果。
给定一个字符串表达式exp及它的长度len,同时给定结果值ret,请返回方案数。保证表达式长度小于等于300。为了防止溢出,请返回答案Mod 10007的值。
测试样例:
“1^0|0|1”,7,0
返回:2
package alex.suda.dp;
import java.util.Scanner;
public class test7 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int len = scanner.nextInt();
String exp = scanner.next();
int ret = scanner.nextInt();
System.out.println(countWays(exp, len, ret));
}
}
// 三维dp矩阵 dp[i][j][z],表示从i到j计算结果为z的所有方法总和,这里z的取值只有0和1两种。
// 构造dp[i][j][z]的方法是对dp[i][k][z]*dp[k+1][j][z]求和,k取值范围从i到j-1
public static int countNum(int[] nums, char[] ops, int ret) {
int n = nums.length;
int[][][] d = new int[n][n][2];
for (int i = 0; i < n; i++) {
if (nums[i] == 1) {
d[i][i][1] = 1;
} else {
d[i][i][0] = 1;
}
}
for (int x = 1; x < n; x++) { // 外循环是各个数字位
for (int i = 0; i < n - x; i++) {
int j = i + x;
for (int k = i; k < j; k++) {
if (d[i][k][0] != 0 && d[k + 1][j][0] != 0) {
int num = cal(0, 0, ops[k]);
d[i][j][num] = (d[i][j][num] + d[i][k][0] * d[k + 1][j][0]) % 10007;
}
if (d[i][k][0] != 0 && d[k + 1][j][1] != 0) {
int num = cal(0, 1, ops[k]);
d[i][j][num] = (d[i][j][num] + d[i][k][0] * d[k + 1][j][1]) % 10007;
}
if (d[i][k][1] != 0 && d[k + 1][j][0] != 0) {
int num = cal(1, 0, ops[k]);
d[i][j][num] = (d[i][j][num] + d[i][k][1] * d[k + 1][j][0]) % 10007;
}
if (d[i][k][1] != 0 && d[k + 1][j][1] != 0) {
int num = cal(1, 1, ops[k]);
d[i][j][num] = (d[i][j][num] + d[i][k][1] * d[k + 1][j][1]) % 10007;
}
}
}
}
return d[0][n - 1][ret];
}
public static int countWays(String exp, int len, int ret) {
char[] cs = exp.toCharArray();
int[] nums = new int[(len + 1) / 2]; // 存放数字位
char[] ops = new char[(len - 1) / 2]; // 存放操作符位
for (int i = 0; i < len; i++) {
if (i % 2 == 0) {
nums[i / 2] = Integer.valueOf(cs[i] - '0');
} else {
ops[i / 2] = cs[i];
}
}
return countNum(nums, ops, ret) % 10007;
}
public static int cal(int a, int b, char op) {
if (op == '^') {
return a ^ b;
} else if (op == '|') {
return a | b;
} else {
return a & b;
}
}
}