AOJ : 2255 - 6/2(1+2)
問題概要
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2255
日本語の問題文なので省略です.
ちなみに, 僕は 6/2(1+2) の答えは 9 だと思います.
アルゴリズム
O(10!)の単純再帰で書きました.
方法は次のような感じ.(説明下手)
ある数式文字列の中の「数字 演算子 数字」という二項演算の文字列は, 必ず計算することができます.
数式の中に, そのような文字列があれば計算して, その計算結果で置換することを繰り返します.
最終的に, 数字ひとつだけの文字列になるはずなので, これでひとつの解ができたとして, setにaddします.
あとは, setのサイズを出力するだけ.
たとえば, 6/2*(1+2) という数式の場合, 計算が可能な二項演算は,
- 6/2
- 1+2
の2つです.
- 2*(1+2)
は右側の項がまだ演算されていないため, すぐに計算することは無理なので, この*の演算はあとまわし.
とすると, 6/2*(1+2) という数式からは, 次の2つの数式が作り出せることがわかります.
- 3*(1+2)
- 6/2*3
以上の作業を繰り返すと,
- 6/2*(1+2)
- 3*(1+2)
- 3*3
- 9 →数字ひとつだけだからひとつの解
- 3*3
- 6/2*3
- 3*3
- 9 →数字ひとつだけだからひとつの解
- 6/6
- 1 →数字ひとつだけだからひとつの解
- 3*3
- 3*(1+2)
となり, 9, 9, 1 の解が得られ, 答えは2となります.
あとは, ひたすら実装する.
プログラム
public class Main{ static final char MINUS = 'M'; static HashSet<Integer> set; static boolean isdigit(char ch){ return '0' <= ch && ch <= '9' || ch == MINUS; } static String replace(String s){ int before = s.length(); while(true){ for(int i=0;i<s.length();i++){ if(s.charAt(i) == '('){ int j = i+1; while(isdigit(s.charAt(j)))j++; if(s.charAt(j) == ')'){ s = s.substring(0,i) + s.substring(i+1,j) + s.substring(j+1); break; } } } if(before == s.length()) return s; before = s.length(); } } static boolean check(String s){ for(int i=0;i<s.length();i++){ if(!isdigit(s.charAt(i))){ return false; } } return true; } static int toInt(String s){ if(s.charAt(0) == MINUS){ return -1 * Integer.parseInt(s.substring(1)); } else{ return Integer.parseInt(s); } } static void solve(String s){ if(check(s)){ set.add(toInt(s)); return; } for(int i=0;i<s.length();i++){ char op = s.charAt(i); if(op != '+' && op != '-' && op != '*' && op != '/') continue; if(!isdigit(s.charAt(i-1)) || !isdigit(s.charAt(i+1))) continue; int l = i-1; int r = i+1; while(l>=0 && isdigit(s.charAt(l))) l--; while(r<s.length() && isdigit(s.charAt(r))) r++; int left = toInt(s.substring(l+1,i)); int right = toInt(s.substring(i+1,r)); int cal = 0; switch(op){ case '+': cal = left + right; break; case '-': cal = left - right; break; case '*': cal = left * right; break; case '/': if(right == 0) continue; cal = left / right; } String next = "" + Math.abs(cal); if(cal < 0) next = MINUS + next; solve(replace( s.substring(0,l+1) + next + s.substring(r) )); } } public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(true){ String s = sc.next(); if(s.equals("#")) break; set = new HashSet<Integer>(); solve(replace(s)); System.out.println(set.size()); } } }