AOJ1152 Dr. Podboq or: How We Became Asymmetric
問題リンク Dr. Podboq or: How We Became Asymmetric
- 解法
入力文字列を構文解析して木を作ってから、木の根から順番に題意を満たすように子を入れ替えて行きます。
木には次の情報を持たせておきます。
rep: このノードを根とする木の文字列表現
sub: このノード以下の部分木で現れる木の集合
id: このノードの番号
left, right: 子の木の番号
num: この部分木のノード数
h: この部分木の高さ
rate: 左右類似度
木の文字列表現は入力文字列と全く同じルールです。
構文解析で木を作る時に、
構造が同じ木を判定できるように子を入れ替え
rep, sub, left, right, num, h, rateの計算
をしています。構造が同じ木なら全く同じ文字列表現になるようにするために、
高さが高い方
同じならノード数が多い方
それも同じなら、repの小さい方
が左の子になるように並び変えています。
入力から木を作ったら、根から順番に題意に沿うように左右の子を比較していきます。
- ソース
import java.util.HashSet; import java.util.Scanner; import java.util.Set; //Dr. Podboq or: How We Became Asymmetric public class AOJ1152 { double EPS = 1e-8; class R{ String rep; Set<String> sub; int id, left, right, num, h; double rate; public R(int id) { this.id = id; rate = left = right = -1; rep = ""; h = num = 1; sub = new HashSet<String>(); } void f(boolean isLeft){ if(left==-1)return; boolean leftStrong = comp(left, right)<=0; if(leftStrong && !isLeft || !leftStrong && isLeft){ int t = left; left = right; right = t; } rs[left].f(true); rs[right].f(false); } int comp(int v1, int v2){ if(Math.abs(rs[v1].rate-rs[v2].rate)>EPS){ return rs[v1].rate < rs[v2].rate?-1:1; } if(rs[v1].left==-1 && rs[v2].left==-1)return 0; int l1 = rs[v1].left, r1 = rs[v1].right, l2 = rs[v2].left, r2 = rs[v2].right; if(comp(l1, r1)==1){ int t = l1; l1 = r1; r1 = t; } if(comp(l2, r2)==1){ int t = l2; l2 = r2; r2 = t; } int c = comp(l1, l2); if(c!=0){ return c; } return comp(r1, r2); } void p(){ if(left==-1)System.out.print("x"); else{ System.out.print("("); rs[left].p(); System.out.print(" "); rs[right].p(); System.out.print(")"); } } void proc(){ if(left==-1){ rate = 0; h = 1; rep = "x"; sub.add(rep); return; } rs[left].proc(); rs[right].proc(); sub.addAll(rs[left].sub); sub.addAll(rs[right].sub); int c = 0; for(String s:sub)if(rs[left].sub.contains(s) && rs[right].sub.contains(s))c++; rate = 1.*c/sub.size(); num+=rs[left].num+rs[right].num; if(rs[left].h < rs[right].h || rs[left].h==rs[right].h&&rs[left].num < rs[right].num || rs[left].h==rs[right].h&&rs[left].num==rs[right].num&&rs[left].rep.compareTo(rs[right].rep)>0){ int t = left; left = right; right = t; } h = Math.max(rs[left].h, rs[right].h)+1; rep = "("+rs[left].rep+" "+rs[right].rep+")"; sub.add(rep); } } R[] rs; int idx, ID; char[] s; char get(){ return s[idx++]; } int tree(){ int res = ID++; rs[res] = new R(res); char ch = get(); if(ch=='x'){ return res; } rs[res].left = tree(); get(); rs[res].right = tree(); get(); return res; } void run(){ Scanner sc = new Scanner(System.in); for(;;){ s = sc.nextLine().toCharArray(); if(s[0]=='0')break; idx = ID = 0; rs = new R[128]; tree(); rs[0].proc(); rs[0].f(true); rs[0].p(); System.out.println(); } } public static void main(String[] args) { new AOJ1152().run(); } }