Problem:
塗りつぶしゲーム

指で画面にタッチして操作することのできるタブレットインターフェースの技術は、ゲームの分野でも応用され、新しい操作感を持つ様々な種類のゲームが作られています。現在、ＡＺ社が開発しているゲームもその一つです。

このソフトウェア（ゲーム）の要件は以下の通りです。

画面には X 列× Y行の2次元グリッドがあります。

グリッドのセルは赤(R)、緑(G)、茶(B)の3色のいずれかで塗られています。

セルの色を変更するボタンR、G、Bがあり、このボタンが押下されると一番左上(0,0)のセルがその色に変更されます。

一番左上のセルの色が変更されると、そのセルの元の色と同じ色に塗られた隣接するすべてのセルが指定された色に変わります。すなわち、元の色が同じ色のセルでつながったセルはすべて指定された色に変更されます。

このようにグリッドを塗りつぶしていき、最終的にグリッド全体を一色にするというゲームです。少ない手順で解くと高得点が与えられます。

ＡＺ社のプログラマーであるあなたは、このゲームのロジックの一部分を開発することになりました。まずは、この最高得点を計算するため、このゲームを最短で解いた場合、最低何回選択ボタンを操作すればグリッドが一色になるかをもとめるプログラムを作ることにしました。

入力

複数のデータセットが与えられます。入力の終わりはゼロふたつで示されます。各データセットは以下の形式で与えられます。

X Y
c1,1 c2,1 ... cX,1
c1,2 c2,2 ... cX,2
:
c1,Y c2,Y ... cX,Y

1行目にグリッドの列と行のサイズ X, Y (2 ≤ X, Y ≤ 10) が与えられます。続く Y 行に i 列目 j 行目のセルの色を表す文字 ci,j が空白区切りで与えられます。

出力

データセットごとに、ボタン操作の最少回数を1行に出力します。

入力例

3 3
R G B
G G G
G B B
2 4
R G
G G
R B
B R
4 3
G G B R
G R R G
B G G R
0 0

出力例

2
4
4

Solution in JAVA (judge verdict: Memory Limit Exceeded)

import java.util.*;

public class Main {
	Scanner in = new Scanner(System.in);
	public static void main(String[] args) {
		new Main();
	}
	public Main(){
		new AOJ0243().doIt();
	}

	class AOJ0243{
		int w,h;
		char[][] map;
		char[][] work;
		int sx[]={1,0,-1,0};
		int sy[]={0,1,0,-1};
		void input(String a){
			int num = 0;
			for(int i=0;i<h;i++)for(int s=0;s<w;s++){
				map[i][s] = a.charAt(num);num++;
			}
		}

		void push(int x,int y,char color){
			if(map[y][x] != map[0][0])return;
			work[y][x] = color;
			for(int i=0;i<4;i++){
				int nx = x+sx[i];
				int ny = y+sy[i];
				if(nx<0||nx>=w||ny<0||ny>=h)continue;
				if(map[ny][nx]!=map[0][0])continue;
				if(work[ny][nx]!=map[ny][nx])continue;
				push(nx, ny, color);
			}
		}

		boolean isGoal(){
			char a = map[0][0];
			for(int i=0;i<h;i++)for(int s=0;s<w;s++)if(a!=map[i][s])return false;
			return true;
		}

		void print(char[][] a){
			for(int i=0;i<h;i++){
				for(int s=0;s<w;s++)System.out.print(a[i][s]);
				System.out.println();
			}
		}

		void solved(){
			LinkedList<State> q = new LinkedList<State>();
			q.add(new State(map, 0));
			HashSet<String> set = new HashSet<String>();
			int result = -1;
			while(!q.isEmpty()){
//				System.out.println("------------------------");
				State now = q.remove();
				if(set.contains(now.field))continue;
				set.add(now.field);
				input(now.field);
//				print(map);
				if(isGoal()){
					result = now.cost;break;
				}
				if(map[0][0]!='R'){
					work = new char[h][w];
					for(int i=0;i<h;i++)for(int s=0;s<w;s++)work[i][s] = map[i][s];
					push(0, 0, 'R');
					q.add(new State(work, now.cost+1));
				}
				input(now.field);
				if(map[0][0]!='G'){
					work = new char[h][w];
					for(int i=0;i<h;i++)for(int s=0;s<w;s++)work[i][s] = map[i][s];
					push(0, 0, 'G');
					q.add(new State(work, now.cost+1));
				}
				input(now.field);
				if(map[0][0]!='B'){
					work = new char[h][w];
					for(int i=0;i<h;i++)for(int s=0;s<w;s++)work[i][s] = map[i][s];
					push(0, 0, 'B');
					q.add(new State(work, now.cost+1));
				}
			}
			System.out.println(result);
		}

		void doIt(){
			while(in.hasNext()){
				w = in.nextInt();
				h = in.nextInt();
				if(w+h==0)break;
				map = new char[h][w];
				for(int i=0;i<h;i++)for(int s=0;s<w;s++)map[i][s] = in.next().charAt(0);
				solved();
			}
		}

		class State{
			String field;
			int cost;
			public State(char[][] map,int cost){
				field = "";
				for(int i=0;i<h;i++)for(int s=0;s<w;s++)field += map[i][s];
				this.cost = cost;
			}
		}

	}

}