AOJ2084 Hit and Blow
問題リンク Hit and Blow
- 概要
Hit and Blowをする。今、N回の試行とその結果が分かっている。試行結果から、答えが1つに定まるならその答えを出力せよ。
そうでなければ新たに数xを試行する。試行し、その結果から解が一意に決まるならばそのxを答えよ。xが複数ある場合は最も小さいものを選ぶこと。そのような数xが1つもなければ"????"と答えよ。
なお、N回の試行の結果にあてはまるような数は常に1つ以上あることが保証されている。
- 解法
N回の試行によって、答えの候補になるような数が求まります。すなわち、0123〜9876の数の中で、N回の試行結果と一致するものが、このHit and Blowの答えの候補となります。得られた候補のリストをLとします。
Lの要素が1つなら、解が一意に定まるので答えとなります。
そうでなければ、理論的に解が1つに定まるような数xを探します。
xは0123〜9876まで全て試すことにします。
このxが解を1つに定めることができる、ということは、「Lの各要素とx」のhitとblowを求めた時、同じ結果になるものが存在しないということです。最初にこれを満たしたxが答えになります。全てのxについて、これが成り立たなかった場合は"????"になります。
- ソース
import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Scanner; import java.util.Set; //Hit and Blow public class AOJ2084 { int get(int x, int k){ return k==0?x/1000:k==1?x/100%10:k==2?x/10%10:x%10; } int[] f(int A, int B){ int[] a = new int[4], b = new int[4]; for(int i=0;i<4;i++){ a[i] = get(A, i); b[i] = get(B, i); } int hit = 0, blow = 0; for(int i=0;i<4;i++)for(int j=0;j<4;j++)if(a[i]==b[j]){ if(i==j)hit++; else blow++; } return new int[]{hit, blow}; } void run(){ boolean[] v = new boolean[10000]; for(int i=123;i<=9876;i++){ Set<Integer> s = new HashSet<Integer>(); for(int j=0;j<4;j++)s.add(get(i, j)); v[i] = s.size()==4; } Scanner sc = new Scanner(System.in); boolean[] cand = new boolean[10000]; int[][] p = new int[5][5]; for(;;){ int n = sc.nextInt(); if(n==0)break; for(int i=0;i<10000;i++)cand[i] = v[i]; int[] x = new int[n], h = new int[n], b = new int[n]; for(int i=0;i<n;i++){ x[i] = sc.nextInt(); h[i] = sc.nextInt(); b[i] = sc.nextInt(); for(int j=123;j<=9876;j++)if(cand[j]){ int[] r = f(j, x[i]); cand[j]&=r[0]==h[i]&&r[1]==b[i]; } } List<Integer> l = new ArrayList<Integer>(); for(int i=123;i<=9876;i++)if(cand[i])l.add(i); if(l.size()==1){ System.out.printf("%04d\n", l.get(0)); continue; } int res = -1; for(int i=123;i<=9876;i++)if(v[i]){ for(int[]a:p)Arrays.fill(a, 0); for(int s:l){ int[] r = f(s, i); p[r[0]][r[1]]++; if(1 < p[r[0]][r[1]])break; } boolean ok = true; for(int j=0;j<5;j++)for(int k=0;k<5;k++)if(1 < p[j][k])ok = false; if(ok){ res = i; break; } } if(res==-1)System.out.println("????"); else System.out.printf("%04d\n", res); } } public static void main(String[] args) { new AOJ2084().run(); } }