AOJ1233 Equals are Equals
問題リンク Equals are Equals
- 概要
多項式Pが与えられる。更に多項式のリストLが与えられるので、これらがPと同値かを判定せよ。
多項式の変数には'a'-'z'が使われる。そのほかは'0'-'9', '(',')', '^', ' ', '+', '-' の文字のみが登場する。
'+', '-'は2項演算子であり、単項演算子として登場することはない。
多項式中に登場する空白は、読みやすさのための空白と、隣り合う整数を区分するためにある。
変数シンボルの後ろに'^'と1桁の0でない整数が続くことがある。
係数はどんなときでも10^9に収まる。また変数の指数部は10に収まる。
- 解法
まず、多項式をクラスとしました。
変数はx, x^2, ab^2c^3など複雑になりうるので辞書順でソートした文字列として表現します。(他に方法があるのかは分かりません)
ex) x^2→"xx", ab^2c^3→"abbccc", ac^3b^2→"abbccc"
この文字列を変数Xとし、Map
それと、定数項c0を持ちます。
2つの多項式クラスp1, p2に対して、和と差と積とべき乗の計算をメソッドとして作ります。
更に、多項式同士を比較するeq()も作っておきます。mapが返す値はIntegerオブジェクトなので係数の比較にはequals()を使いましょう。
次に構文解析の部分についてです。例によってBFSを作ってみます。正確な表記ではないのでノリを感じてください。
Exp = Term '+' Exp | Term '-' Exp | Term
Term = Fact + {0個以上の空白 + Fact}
Fact = 'a'-'z' ('^' + '1'-'9') | 整数 | '(' Exp ')'
あとはこれをメソッドの形で実装します。空白を飛ばして次の文字トークンを取得するメソッドと、直後の文字トークンを取得するメソッドの2つを使い分ける必要があると思います。
- ソース
import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; //Equals are Equals public class AOJ1233 { char[] s; int id; class P{ Map<String, Integer> c; int c0; public P() { c = new HashMap<String, Integer>(); c0 = 0; } boolean eq(P p){ if(c.size()!=p.c.size()||c0!=p.c0)return false; for(String t:c.keySet())if(!p.c.containsKey(t)||!c.get(t).equals(p.c.get(t)))return false; return true; } P add(P p){ P r = new P(); for(String t:c.keySet()){ if(p.c.containsKey(t))r.c.put(t, c.get(t)+p.c.get(t)); else r.c.put(t, c.get(t)); } for(String t:p.c.keySet()){ if(!c.containsKey(t))r.c.put(t, p.c.get(t)); } r.c0 = c0+p.c0; Set<String> set = new HashSet<String>(); for(String t:r.c.keySet())if(r.c.get(t)==0)set.add(t); for(String t:set)r.c.remove(t); return r; } P sub(P p){ P r = new P(); for(String t:c.keySet()){ if(p.c.containsKey(t))r.c.put(t, c.get(t)-p.c.get(t)); else r.c.put(t, c.get(t)); } for(String t:p.c.keySet()){ if(!c.containsKey(t))r.c.put(t, -p.c.get(t)); } r.c0 = c0-p.c0; Set<String> set = new HashSet<String>(); for(String t:r.c.keySet())if(r.c.get(t)==0)set.add(t); for(String t:set)r.c.remove(t); return r; } P mul(P p){ P r = new P(); for(String s:c.keySet())for(String t:p.c.keySet()){ char[] x = (s+t).toCharArray(); Arrays.sort(x); String v = new String(x); if(r.c.containsKey(v))r.c.put(v, r.c.get(v)+c.get(s)*p.c.get(t)); else r.c.put(v, c.get(s)*p.c.get(t)); } for(String s:c.keySet()){ if(r.c.containsKey(s))r.c.put(s, r.c.get(s)+p.c0*c.get(s)); else r.c.put(s, p.c0*c.get(s)); } for(String s:p.c.keySet()){ if(r.c.containsKey(s))r.c.put(s, r.c.get(s)+c0*p.c.get(s)); else r.c.put(s, c0*p.c.get(s)); } r.c0 += c0*p.c0; Set<String> set = new HashSet<String>(); for(String t:r.c.keySet())if(r.c.get(t)==0)set.add(t); for(String t:set)r.c.remove(t); return r; } P pow(int k){ P r = new P(); r.c0 = 1; while(k--!=0)r = r.mul(this); return r; } @Override public String toString() { String r = ""; for(String t:c.keySet())r+=" "+c.get(t)+t; r+=" "+c0; return r; } } char get(){ return s[id++]; } char next(){ while(s[id]==' ')id++; return s[id++]; } P exp(){ P r = term(); char ch = next(); while(ch=='+'||ch=='-'){ P f = term(); if(ch=='+')r = r.add(f); else r = r.sub(f); ch = next(); } id--; return r; } P term(){ P r = fact(); char ch = next(); while(Character.isDigit(ch)||Character.isLowerCase(ch)||ch=='('){ id--; P f = fact(); r = r.mul(f); ch = next(); } id--; return r; } P fact(){ char ch = next(); P r = new P(); if(ch=='('){ r = exp(); next(); } else if(Character.isLowerCase(ch))r.c.put(ch+"", 1); else if(Character.isDigit(ch)){ int x = ch-'0'; for(;;){ ch = get(); if(!Character.isDigit(ch)){ id--;break; } x = x*10 + ch-'0'; } r.c0 = x; } ch = next(); while(ch=='^'){ int x = next()-'0'; r = r.pow(x); ch = next(); } id--; return r; } void run(){ Scanner sc = new Scanner(System.in); for(;;){ s = (sc.nextLine()+"$").toCharArray(); if(s[0]=='.')break; id = 0; P ans = exp(); for(;;){ s = (sc.nextLine()+"$").toCharArray(); if(s[0]=='.')break; id = 0; P p = exp(); System.out.println(ans.eq(p)?"yes":"no"); } System.out.println("."); } } public static void main(String[] args) { new AOJ1233().run(); } }