土下座しながら探索中

主に競技プログラミング

SEERC 2015 A : Equivalence

問題リンク : https://icpcarchive.ecs.baylor.edu/external/71/7173.pdf

問題概要 :
2つの論理式が与えられる
それらが等価か判定せよ

論理式は論理変数、論理和論理積、否定から構成される
論理演算の優先度は気にしなくても良い(適切に括弧がつけられている)
論理式に含まれる論理変数は高々51個

解法:
BDDで解いた
最悪ケースが大丈夫なのか謎ではあったが、、
BDD自体は北大の授業のスライドを参考に作成
codeforcesのGYMで他の人のコードを見たら皆乱数で適当に変数に値を割り当てて評価し、適当な回数だけ繰り返し評価を行い全て一致するかどうかで判定していた
LiveArchiveはまだジャッジが用意されていないようなのでジャッジ待ち

コード:

import java.io.*;
import java.util.*;


class BinaryOperatorMemoState implements Comparable<BinaryOperatorMemoState> {
	public char op;
	public int F, G;

	public BinaryOperatorMemoState() {

	}

	public BinaryOperatorMemoState(char op, int F, int G) {
		this.op = op;
		this.F = F;
		this.G = G;
	}

	@Override
	public int compareTo(BinaryOperatorMemoState o) {
		int result = new Character(this.op).compareTo(o.op);
		if (result == 0) {
			result = new Integer(this.F).compareTo(o.F);
			if (result == 0) {
				result = new Integer(this.G).compareTo(o.G);
			}
		}
		return result;
	}
}

class BooleanExpression {
	public BooleanExpression deepCopy() {
		System.out.println("WARNING");
		return this.deepCopy();
	}

	public BooleanExpression assignBooleanValueToLogicVariable(boolean booleanValue, LogicVariable logicVariable) {
		System.out.println("WARNING");
		return this.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
	}

	public int traverse() {
		System.out.println("WARNING");
		return -1;
	}

	public boolean eval(HashSet<State> F, HashSet<State> L) {
		System.out.println("WARNING");
		return false;
	}

	public BooleanExpression recoverPredicate() {
		System.out.println("WARNING");
		return this.recoverPredicate();
	}

}


class And extends BooleanExpression {
	public BooleanExpression left, right;

	public And() {

	}

	public And(BooleanExpression left, BooleanExpression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public int traverse() {
		int F = this.left.traverse();
		int G = this.right.traverse();
		return BDD.apply('&', F, G);
	}

	@Override
	public And deepCopy() {
		return new And(left.deepCopy(), right.deepCopy());
	}

	@Override
	public And recoverPredicate() {
		return new And(left.recoverPredicate(), right.recoverPredicate());
	}

	@Override
	public BooleanExpression assignBooleanValueToLogicVariable(boolean booleanValue, LogicVariable logicVariable) {
		BooleanExpression tmp_left = left.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
		BooleanExpression tmp_right = right.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
		if ((tmp_left instanceof LogicVariable) && (tmp_right instanceof LogicVariable)) {
			boolean leftHasValue = ((LogicVariable) tmp_left).hasValue();
			boolean rightHasValue = ((LogicVariable) tmp_right).hasValue();
			if (leftHasValue && rightHasValue) {
				return new LogicVariable(-1, ((LogicVariable) tmp_left).getValue() && ((LogicVariable) tmp_right).getValue());
			} else if (leftHasValue) {
				if (!((LogicVariable) tmp_left).getValue()) {
					return new LogicVariable(-1, false);
				} else {
					return tmp_right;
				}
			} else if (rightHasValue) {
				if (!((LogicVariable) tmp_right).getValue()) {
					return new LogicVariable(-1, false);
				} else {
					return tmp_left;
				}
			} else {
				return new And(tmp_left, tmp_right);
			}
		} else if (tmp_left instanceof LogicVariable) {
			if (((LogicVariable) tmp_left).hasValue()) {
				if (!((LogicVariable) tmp_left).getValue()) {
					return new LogicVariable(-1, false);
				} else {
					return tmp_right;
				}
			} else {
				return new And(tmp_left, tmp_right);
			}
		} else if (tmp_right instanceof LogicVariable) {
			if (((LogicVariable) tmp_right).hasValue()) {
				if (!((LogicVariable) tmp_right).getValue()) {
					return new LogicVariable(-1, false);
				} else {
					return tmp_left;
				}
			} else {
				return new And(tmp_left, tmp_right);
			}
		} else {
			return new And(tmp_left, tmp_right);
		}
	}

	@Override
	public boolean eval(HashSet<State> F, HashSet<State> L) {
		return left.eval(F, L) && right.eval(F, L);
	}

	@Override
	public String toString() {
		return "(" + left + "&" + right + ")";
	}

}

class LogicVariable extends BooleanExpression {
	int ID;
	byte value;

	public LogicVariable() {
		this.value = -1;
	}

	public LogicVariable(int ID) {
		this.ID = ID;
		this.value = -1;
	}

	public LogicVariable(int ID, byte value) {
		this.ID = ID;
		this.value = value;
	}

	public LogicVariable(int ID, boolean value) {
		this.ID = ID;
		this.value = (byte) ((value == true) ? 1 : 0);
	}

	@Override
	public int traverse() {
		if (this.hasValue()) {
			return this.getValue() ? 1 : 0;
		}
		return BDD.getNode(new BDDNode(this.ID, 0, 1));
	}

	@Override
	public LogicVariable deepCopy() {
		return new LogicVariable(ID, value);
	}

	@Override
	public LogicVariable recoverPredicate() {
		return new LogicVariable(((ID < 0) ? -ID : ID), value);
	}

	@Override
	public BooleanExpression assignBooleanValueToLogicVariable(boolean booleanValue, LogicVariable logicVariable) {
		if (ID == logicVariable.getID()) {
			return new LogicVariable(-1, booleanValue);
		}
		return this.deepCopy();
	}

	public boolean hasValue() {
		return this.value != -1;
	}

	public boolean getValue() {
		return this.value == 1;
	}

	public boolean isFalse() {
		return this.hasValue() && !getValue();
	}

	public boolean isTrue() {
		return this.hasValue() && getValue();
	}

	public void setValue(boolean value) {
		this.value = (byte) (value ? 1 : 0);
	}

	public void reverseValue() {
		if (this.value != -1) {
			this.value = (byte) ((this.value == 1) ? 0 : 1);
		}
	}

	public int getID() {
		return this.ID;
	}

	@Override
	public boolean eval(HashSet<State> F, HashSet<State> L) {
		if (ID == -1) {
			if (value == -1) {
				System.out.println("What is this Logic Variable");
			}
			if (value == 1) {
				return true;
			} else {
				return false;
			}
		}
		return F.contains(new State(ID)) || L.contains(new State(ID));
	}

	@Override
	public String toString() {
		if (ID == -1) {
			if (value == -1) {
				System.out.println("What is this Logic Variable");
			}
			if (value == 1) {
				return "true";
			} else {
				return "false";
			}
		}
		return String.valueOf(ID);
	}

}

class Not extends BooleanExpression {
	public BooleanExpression inner;

	public Not() {

	}

	public Not(BooleanExpression inner) {
		this.inner = inner;
	}

	@Override
	public int traverse() {
		int address = inner.traverse();
		return this.notApply(address);
	}

	public int notApply(int address) {
		if (address == 0 || address == 1) {
			return (address == 0) ? 1 : 0;
		}
		BDDNode bn = BDD.nodeTable[address];
		int H0 = notApply(bn.zeroID);
		int H1 = notApply(bn.oneID);
		return BDD.getNode(new BDDNode(bn.variableID, H0, H1));
	}

	@Override
	public Not deepCopy() {
		return new Not(inner.deepCopy());
	}

	@Override
	public Not recoverPredicate() {
		return new Not(inner.recoverPredicate());
	}

	@Override
	public BooleanExpression assignBooleanValueToLogicVariable(boolean booleanValue, LogicVariable logicVariable) {
		BooleanExpression tmp = inner.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
		if (tmp instanceof LogicVariable) {
			if (((LogicVariable) tmp).hasValue()) {
				((LogicVariable) tmp).reverseValue();
				return tmp;
			}
		}
		return new Not(tmp);
	}

	@Override
	public boolean eval(HashSet<State> F, HashSet<State> L) {
		return !inner.eval(F, L);
	}

	@Override
	public String toString() {
		return "!(" + inner + ")";
	}
}

class Or extends BooleanExpression {
	public BooleanExpression left, right;

	public Or() {

	}

	public Or(BooleanExpression left, BooleanExpression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public int traverse() {
		int F = left.traverse();
		int G = right.traverse();
		return BDD.apply('|', F, G);
	}

	@Override
	public Or deepCopy() {
		return new Or(left.deepCopy(), right.deepCopy());
	}

	@Override
	public Or recoverPredicate() {
		return new Or(left.recoverPredicate(), right.recoverPredicate());
	}

	@Override
	public BooleanExpression assignBooleanValueToLogicVariable(boolean booleanValue, LogicVariable logicVariable) {
		BooleanExpression tmp_left = left.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
		BooleanExpression tmp_right = right.assignBooleanValueToLogicVariable(booleanValue, logicVariable);
		if ((tmp_left instanceof LogicVariable) && (tmp_right instanceof LogicVariable)) {
			boolean leftHasValue = ((LogicVariable) tmp_left).hasValue();
			boolean rightHasValue = ((LogicVariable) tmp_right).hasValue();
			if (leftHasValue && rightHasValue) {
				return new LogicVariable(-1, ((LogicVariable) tmp_left).getValue() || ((LogicVariable) tmp_right).getValue());
			} else if (leftHasValue) {
				if (((LogicVariable) tmp_left).getValue()) {
					return new LogicVariable(-1, true);
				} else {
					return tmp_right;
				}
			} else if (rightHasValue) {
				if (((LogicVariable) tmp_right).getValue()) {
					return new LogicVariable(-1, true);
				} else {
					return tmp_left;
				}
			} else {
				return new Or(tmp_left, tmp_right);
			}
		} else if (tmp_left instanceof LogicVariable) {
			if (((LogicVariable) tmp_left).hasValue()) {
				if (((LogicVariable) tmp_left).getValue()) {
					return new LogicVariable(-1, true);
				} else {
					return tmp_right;
				}
			} else {
				return new Or(tmp_left, tmp_right);
			}
		} else if (tmp_right instanceof LogicVariable) {
			if (((LogicVariable) tmp_right).hasValue()) {
				if (((LogicVariable) tmp_right).getValue()) {
					return new LogicVariable(-1, true);
				} else {
					return tmp_left;
				}
			} else {
				return new Or(tmp_left, tmp_right);
			}
		} else {
			return new Or(tmp_left, tmp_right);
		}
	}

	@Override
	public boolean eval(HashSet<State> F, HashSet<State> L) {
		return left.eval(F, L) || right.eval(F, L);
	}

	@Override
	public String toString() {
		return "(" + left + "|" + right + ")";
	}
}

class BDDNode implements Comparable<BDDNode> {
	public int variableID, zeroID, oneID;

	public BDDNode() {
	}

	public BDDNode(int variableID, int zeroID, int oneID) {
		this.variableID = variableID;
		this.zeroID = zeroID;
		this.oneID = oneID;
	}

	public BDDNode deepCopy() {
		return new BDDNode(this.variableID, this.zeroID, this.oneID);
	}

	public boolean equals(BDDNode o) {
		return variableID == o.variableID && zeroID == o.zeroID && oneID == o.oneID;
	}

	@Override
	public int compareTo(BDDNode o) {
		int result = new Integer(this.variableID).compareTo(o.variableID);
		if (result == 0) {
			result = new Integer(this.zeroID).compareTo(o.zeroID);
			if (result == 0) {
				result = new Integer(this.oneID).compareTo(o.oneID);
			}
		}
		return result;
	}

	@Override
	public String toString() {
		return "(" + variableID + "," + zeroID + "," + oneID + ")";
	}
}

//Reference : http://www-erato.ist.hokudai.ac.jp/html/php/seminar5_docs/minato_alg2010-5.pdf
class BDD {
	public static int MAX_TABLE_SIZE = 10000000;
	private static int topOfNodeTable;
	public static BDDNode[] nodeTable = null; // 0番地は0定数節点,1番地は1定数節点
	public static TreeMap<BDDNode, Integer> nodeTableCache;
	public static TreeMap<BinaryOperatorMemoState, Integer> binaryOperatorCache;

	public int addressOfNodeTable;

	public BDD() {
		if (nodeTable == null) {
			nodeTable = new BDDNode[MAX_TABLE_SIZE];
			nodeTable[0] = new BDDNode(-1, -1, -1);
			nodeTable[1] = new BDDNode(-1, -1, -1);
			topOfNodeTable = 2;
			nodeTableCache = new TreeMap<BDDNode, Integer>();
			binaryOperatorCache = new TreeMap<BinaryOperatorMemoState, Integer>();
		}
	}

	public BDD(BooleanExpression be) {
		this();
		addressOfNodeTable = build(be);
	}

	public int build(BooleanExpression be) {
		return be.traverse();
	}

	public static int getNode(BDDNode bn) {
		if (bn.zeroID == bn.oneID) {
			return bn.zeroID;
		}

		if (nodeTableCache.containsKey(bn.deepCopy())) {
			return nodeTableCache.get(bn.deepCopy());
		}
		if (topOfNodeTable >= MAX_TABLE_SIZE) {
			System.out.println("FATAL ERROR : NODE TABLE => OVERFLOW : size : " + topOfNodeTable + " capacity : " + MAX_TABLE_SIZE);
		}

		nodeTable[topOfNodeTable] = bn.deepCopy();
		nodeTableCache.put(bn.deepCopy(), topOfNodeTable);
		return topOfNodeTable++;
	}

	public static boolean isConst(int address) {
		return address == 0 || address == 1;
	}

	public static int apply(char op, int F, int G) {
		// 1. F,Gのいずれかが定数のとき、およびF=Gのとき
		if (isConst(F) || isConst(G) || F == G) {
			if (F == G) {
				return F;
			}
			if (op == '|') {
				if (isConst(F) && isConst(G))
					return F | G;
				if (isConst(F)) {
					int tmp = F;
					F = G;
					G = tmp;
				}
				if (G == 0) {
					return F;
				} else {
					return 1;
				}
			} else if (op == '&') {
				if (isConst(F) && isConst(G))
					return F & G;
				if (isConst(F)) {
					int tmp = F;
					F = G;
					G = tmp;
				}
				if (G == 0) {
					return 0;
				} else {
					return F;
				}
			} else {
				System.out.println("INVALID OPERATOR : WHAT IS " + op + "?");
			}
		}

		BinaryOperatorMemoState boms = new BinaryOperatorMemoState(op, F, G);
		if (binaryOperatorCache.containsKey(boms)) {
			return binaryOperatorCache.get(boms);
		}

		// 2.両者の最上位変数F.vとG.vが同じとき
		BDDNode bnF = nodeTable[F].deepCopy(); // deepCopyでないと手順4を実行した場合にnodeTableの値が書きかわるので注意
		BDDNode bnG = nodeTable[G].deepCopy();
		if (bnF.variableID == bnG.variableID) {
			int H0 = apply(op, bnF.zeroID, bnG.zeroID);
			int H1 = apply(op, bnF.oneID, bnG.oneID);
			if (H0 == H1) {
				binaryOperatorCache.put(boms, H0);
				return H0;
			}
			int address = getNode(new BDDNode(bnF.variableID, H0, H1));
			binaryOperatorCache.put(boms, address);
			return address;
		}
		// 変数の番号が大きいほど下位であることに注意
		// 4.F.vがG.vよりも下位のとき
		// FとGを入れ替えて、3.と同様に処理
		if (bnF.variableID > bnG.variableID) {
			int tmp = F;
			F = G;
			G = tmp;
			bnF = nodeTable[F].deepCopy();
			bnG = nodeTable[G].deepCopy();
		}

		// 3.F.vがG.vよりも上位のとき
		int H0 = apply(op, bnF.zeroID, G);
		int H1 = apply(op, bnF.oneID, G);
		if (H0 == H1) {
			binaryOperatorCache.put(boms, H0);
			return H0;
		}
		int address = getNode(new BDDNode(bnF.variableID, H0, H1));
		binaryOperatorCache.put(boms, address);
		return address;
	}

	public static void printNodeTable() {
		System.out.println("table size = " + topOfNodeTable);
		for (int i = 0; i < topOfNodeTable; i++) {
			BDDNode bn = nodeTable[i];
			System.out.println(i + "-th : " + bn);
		}
	}

	public boolean equals(BDD bdd) {
		// System.out.println("bdd1 = " + this.addressOfNodeTable);
		// System.out.println("bdd2 = " + bdd.addressOfNodeTable);
		return this.addressOfNodeTable == bdd.addressOfNodeTable;
	}

	public static int getNodeTableSize() {
		return topOfNodeTable;
	}

}

class State {
	private int ID;

	public State() {

	}

	public State(int ID) {
		this.ID = ID;
	}

	public void setID(int ID) {
		this.ID = ID;
	}

	public int getID() {
		return this.ID;
	}

	@Override
	public String toString() {
		return String.valueOf(ID);
	}

	@Override
	public int hashCode() {
		return new Integer(ID).hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj != null && obj instanceof State) {
			final State state = (State) obj;
			return this.getID() == state.getID();
		}
		return false;
	}

	public int compareTo(State state) {
		return new Integer(ID).compareTo(state.getID());
	}

}

class BooleanExpressionEvaluator {
	private String context;
	private int currentPosition;

	public BooleanExpressionEvaluator(String context) {
		this.context = context;
		currentPosition = 0;
	}

	BooleanExpression fact() {
		boolean not_coef = false;
		if (context.charAt(currentPosition) == '~') {
			++currentPosition;
			not_coef = true;
		}
        BooleanExpression be = null;
		if (context.charAt(currentPosition) == '(') {
			++currentPosition;
			be = exp();
			++currentPosition;
		} else {
            int ID = context.charAt(currentPosition++);
            be = new LogicVariable(ID);
		}
		if (not_coef) {
            be = new Not(be);
		}
		return be;
	}

	BooleanExpression exp() {
		BooleanExpression state1 = fact();
		while (currentPosition < context.length() && (context.charAt(currentPosition) == 'V' || context.charAt(currentPosition) == '^')) {
			char opr = context.charAt(currentPosition++);
			BooleanExpression state2 = fact();
			if (opr == 'V') {
                state1 = new Or(state1,state2);
			} else {
                state1 = new And(state1,state2);
			}
		}
		return state1;
	}

	public BooleanExpression eval() {
		return exp();
	}

}

class Main {    
    public static BooleanExpression toBooleanExpression(String s) {
        BooleanExpressionEvaluator bee = new BooleanExpressionEvaluator(s);
        return bee.eval();
    }

    public static int exec(String p1,String p2) {
        BDD bdd = new BDD();
        BooleanExpression be_p1 = toBooleanExpression(p1);
        BooleanExpression be_p2 = toBooleanExpression(p2);
        return (bdd.build(be_p1) == bdd.build(be_p2))?1:0;
    }

    public static String removeSpace(String s) {
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<s.length();i++) if( s.charAt(i) != ' ' ) {
                sb.append(s.charAt(i));
        }
        return sb.toString();
    }
    
    public static void main(String args[]) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        while(true) {
        String p1 = in.readLine();
        if( p1 == null )break;
        String p2 = in.readLine();
        p1 = removeSpace(p1);
        p2 = removeSpace(p2);
        //System.out.println(p1 + " ?= " + p2);
        System.out.println(exec(p1,p2));
        }
    }
}