[编程题]表达式组成方案

对于一个只由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;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值