package Question9_11;
import java.util.HashMap;
public class Question {
public enum Term {
True,
False,
And,
Or,
Xor,
LeftParen,
RightParen
};
public static String reduce(String expression, int start, int end) {
if (start == end) {
if (expression.charAt(start) == '1') {
return "1";
} else if (expression.charAt(start) == '0') {
return "0";
}
}
int count = 0;
int i = 0;
String[] reduced = new String[3];
int index = 0;
int left = start;
int right = start;
for (i = start; i <= end; i++) {
if (expression.charAt(i) == '(') {
if (count == 0) {
left = i + 1;
}
count++;
} else if (expression.charAt(i) == ')') {
count--;
if (count == 0) {
right = i - 1;
}
}
if (count == 0) {
reduced[index] = reduce(expression, left, right);
if (index == 0) {
reduced[index + 1] = Character.toString(expression.charAt(i + 1));
i += 1;
left = i + 1;
right = i + 1;
}
index += 2;
}
}
if (reduced[1].equals("&")) {
if (reduced[0].equals("1") && reduced[2].equals("1")) {
return "1";
}
return "0";
} else if (reduced[1].equals("|")) {
if (reduced[0].equals("1") || reduced[2].equals("1")) {
return "1";
}
return "0";
} else if (reduced[1].equals("^")) {
if (reduced[0].equals("1") && reduced[2].equals("0")) {
return "1";
} else if (reduced[0].equals("0") && reduced[2].equals("1")) {
return "1";
}
return "0";
}
return "0";
}
public static boolean evaluate(String expression, int start, int end) {
String result = reduce(expression, start, end);
if (result == "0") {
return false;
} else {
return true;
}
}
public static boolean isOperator(char c) {
switch (c) {
case '&':
case '|':
case '^':
return true;
default:
return false;
}
}
public static String insertParensAround(String expression, int ind) {
int left = 0;
int right = 0;
int index = 0;
int count = 0;
for (int i = 0; i < expression.length(); i++) {
if (isOperator(expression.charAt(i))) {
if (count == ind) {
index = i;
}
count++;
}
}
count = 0;
for (int i = index - 1; i >= 0; i--) {
if (expression.charAt(i) == ')') {
count++;
} else if (expression.charAt(i) == '(') {
count--;
}
if (count == 0) {
left = i;
break;
}
}
count = 0;
for (int i = index + 1; i <= expression.length(); i++) {
if (expression.charAt(i) == '(') {
count++;
} else if (expression.charAt(i) == ')') {
count--;
}
if (count == 0) {
right = i;
break;
}
}
if (left == 0 && right == expression.length() - 1) {
return expression;
}
String newexpression = expression.substring(0, left) + '(' + expression.substring(left, right + 1) + ')' + expression.substring(right + 1);
return newexpression;
}
public static int bruteForce(String expression, HashMap<String, Boolean> completed, boolean result, boolean[] flags) {
int count = 0;
boolean isDone = true;
if (completed.containsKey(expression)) {
return 0;
}
for (int i = 0; i < flags.length; i++) {
if (!flags[i]) {
flags[i] = true;
String newexpression = insertParensAround(expression, i);
isDone = false;
count += bruteForce(newexpression, completed, result, flags);
flags[i] = false;
}
}
if (isDone) {
if (evaluate(expression, 0, expression.length() - 1) == result) {
System.out.println(expression + " = " + result);
return 1;
} else {
System.out.println(expression + " = " + !result);
return 0;
}
}
completed.put(expression, true);
return count;
}
public static int countR(String exp, boolean result, int start, int end) {
if (start == end) {
if (exp.charAt(start) == '1' && result) {
return 1;
} else if (exp.charAt(start) == '0' && !result) {
return 1;
}
return 0;
}
int c = 0;
if (result) {
for (int i = start + 1; i <= end; i += 2) {
char op = exp.charAt(i);
if (op == '&') {
c += countR(exp, true, start, i - 1) * countR(exp, true, i + 1, end);
} else if (op == '|') {
c += countR(exp, true, start, i - 1) * countR(exp, false, i + 1, end);
c += countR(exp, false, start, i - 1) * countR(exp, true, i + 1, end);
c += countR(exp, true, start, i - 1) * countR(exp, true, i + 1, end);
} else if (op == '^') {
c += countR(exp, true, start, i - 1) * countR(exp, false, i + 1, end);
c += countR(exp, false, start, i - 1) * countR(exp, true, i + 1, end);
}
}
} else {
for (int i = start + 1; i <= end; i += 2) {
char op = exp.charAt(i);
if (op == '&') {
c += countR(exp, false, start, i - 1) * countR(exp, true, i + 1, end);
c += countR(exp, true, start, i - 1) * countR(exp, false, i + 1, end);
c += countR(exp, false, start, i - 1) * countR(exp, false, i + 1, end);
} else if (op == '|') {
c += countR(exp, false, start, i - 1) * countR(exp, false, i + 1, end);
} else if (op == '^') {
c += countR(exp, true, start, i - 1) * countR(exp, true, i + 1, end);
c += countR(exp, false, start, i - 1) * countR(exp, false, i + 1, end);
}
}
}
return c;
}
public static int countDP(String exp, boolean result, int start, int end, HashMap<String, Integer> cache) {
String key = "" + result + start + end;
if (cache.containsKey(key)) {
return cache.get(key);
}
if (start == end) {
if (exp.charAt(start) == '1' && result == true) {
return 1;
} else if (exp.charAt(start) == '0' && result == false) {
return 1;
}
return 0;
}
int count = 0;
if (result) {
for (int i = start + 1; i <= end; i += 2) {
char op = exp.charAt(i);
if (op == '&') {
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
} else if (op == '|') {
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
} else if (op == '^') {
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
}
}
} else {
for (int i = start + 1; i <= end; i += 2) {
char op = exp.charAt(i);
if (op == '&') {
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
} else if (op == '|') {
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
} else if (op == '^') {
count += countDP(exp, true, start, i - 1, cache) * countDP(exp, true, i + 1, end, cache);
count += countDP(exp, false, start, i - 1, cache) * countDP(exp, false, i + 1, end, cache);
}
}
}
cache.put(key, count);
return count;
}
public static int total(int n) {
// Function to return (2n) ! / ((n+1)! * n!)
// To keep the numbers small, we divide by i when possible to do evenly. If not,
// we store up the remainder and divide when possible.
long num = 1;
long rem = 1;
for (int i = 2; i <= n; i++) {
num *= (n + i);
rem *= i;
if (num % rem == 0) {
num /= rem;
rem = 1;
}
}
return (int)num;
}
public static int countDPEff(String exp, boolean result, int start, int end, HashMap<String, Integer> cache) {
String key = "" + start + end;
int count = 0;
if (!cache.containsKey(key)) {
if (start == end) {
if (exp.charAt(start) == '1') {
count = 1;
} else {
count = 0;
}
}
for (int i = start + 1; i <= end; i += 2) {
char op = exp.charAt(i);
if (op == '&') {
count += countDPEff(exp, true, start, i - 1, cache) * countDPEff(exp, true, i + 1, end, cache);
} else if (op == '|') {
int left_ops = (i - 1 - start) / 2; // parens on left
int right_ops = (end - i - 1) / 2; // parens on right
int total_ways = total(left_ops) * total(right_ops);
int total_false = countDPEff(exp, false, start, i - 1, cache) * countDPEff(exp, false, i + 1, end, cache);
count += total_ways - total_false;
} else if (op == '^') {
count += countDPEff(exp, true, start, i - 1, cache) * countDPEff(exp, false, i + 1, end, cache);
count += countDPEff(exp, false, start, i - 1, cache) * countDPEff(exp, true, i + 1, end, cache);
}
}
cache.put(key, count);
} else {
count = cache.get(key);
}
if (result) {
return count;
} else {
int num_ops = (end - start) / 2;
return total(num_ops) - count;
}
}
public static void main(String[] args) {
String terms = "0^0|1&1^1|0|1";
boolean result = true;
bruteForce(terms, new HashMap<String, Boolean>(), result, new boolean[(terms.length() - 1) / 2]);
System.out.println(countR(terms, result, 0, terms.length() - 1));
System.out.println(countDP(terms, result, 0, terms.length() - 1, new HashMap<String, Integer>()));
System.out.println(countDPEff(terms, result, 0, terms.length() - 1, new HashMap<String, Integer>()));
}
}