Problem:
Problem D: 伝説の剣

※ この問題には厨二成分が多く含まれます。胸焼けにご注意ください。

ついに復活を遂げた魔王は、再び世界を闇に包むために人間界に攻め入ろうとしていた。

魔王は、本格的な侵攻を始める前に、まず伝説の剣を破壊することにした。
前回の戦争において、魔王は伝説の剣を持つ勇者によって倒された。
魔王の体は闇の衣によって守られているため、生半可な攻撃では魔王を傷つけることはできない。
しかし、伝説の剣は、神々の加護により、魔王の闇の衣すら容易に貫いてしまう。
そのため、今回の戦争に勝利するためには、なんとしてもその伝説の剣を手に入れて破壊する必要がある。

調査の末、伝説の剣はとある遺跡の最奥に安置され、次代の勇者が現われるのを待っていることがわかった。
伝説の剣は、邪悪な者や盗賊によって奪われるのを防ぐために、周囲に点在する無数の宝珠によって封印されている。
魔王は、強力な魔力を持っているため、触れるだけで宝珠を破壊することができる。
ただし、宝珠による封印は多重構造になっており、表層から順に破壊していく必要がある。
例えば、第1の封印の宝珠を破壊する前に第2以降の封印の宝珠に触れたとしても、破壊することはできない。
また、複数の宝珠が同じ封印を構成していることもあるが、魔王はそのうちの一つに触れるだけで、同時にその封印を破壊することができる。

遺跡には神聖な力が満ちており、並の魔物では入ることすらままならない。
そこで、魔王自ら赴き伝説の剣を回収してくることになった。
いかに魔王といえど、長時間その力を受け続ければただではすまない。
魔王の右腕であるあなたの仕事は、念のため魔王が全ての封印を破壊し、伝説の剣の下に辿りつくまでの時間を求めることである。

Input

入力は、複数のデータセットからなり、入力の終わりはスペースで区切られたゼロ二つからなる行である。
データセットの総数は50以下である。
各データセットは、次の形式をしている。

w h
s(1,1) ... s(1,w)
s(2,1) ... s(2,w)
...
s(h,1) ... s(h,w)

wとhは、それぞれ遺跡のフロアを表現する行列データの幅と高さを示す整数であり、それぞれ1 ≤ w, h ≤ 100であり、2 ≤ w + h ≤ 100と仮定して良い。
続くh行はそれぞれ、スペースで区切られたw個の文字から構成されており、文字s(y,x)は、座標(y,x)の地点の状態を示す。

その意味は、以下の通りである。

S：魔王が最初にいる地点。フロアに必ず1つだけ存在する。

G：伝説の剣の地点。必ず1つだけ存在する。

.：なにもない。

数字：宝珠がある地点。数字は構成する封印の番号を示す。数字は1以上の整数であり、間の数字に抜けはないとしてよい。

また、魔王は、遺跡のフロア内の上下左右の隣接する座標に移動することができ、その移動にかかる時間を1とする。
破壊できる宝珠は触れるだけで破壊できるため、宝珠の破壊には時間はかからない。

Output

各データセットに対して、魔王が全ての封印を破壊し、伝説に剣に辿りつくために必要な最短時間を出力せよ。

Sample Input

10 10
S . . . . . . . . .
. . . . . . . . . .
. . . . 1 . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . 3 . .
. . . . . . . . . .
. . . . . 4 . . . .
. . . . . . . . . .
2 . . . . . . . . G
10 10
S . . . . . 3 . . .
. . 3 . . . . . . .
. . . . 1 . . . . .
. . . . . . 4 . . .
. . 3 . . . 1 . . .
. . . . . . . 3 . .
. . . . . . . . . .
. . . . . 4 . . . .
. . . . . 5 . . . .
2 . . . . . . . . G
10 10
S . . . . . . . . 1
. . . . . 5 . . . .
. 4 . . . . . . . .
. . . . 8 . 9 . . .
. . . . 10 . . . . .
. . 7 . G . . . . .
. . . 11 . . . . . .
3 . . . . . . . . 6
. . . . . . . 2 . .
. . . . . . . . . .
0 0

Output for Sample Input

38
36
71

Solution in JAVA (judge verdict: Memory Limit Exceeded)

import java.util.*;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		while (true) {
			int w = sc.nextInt();
			int h = sc.nextInt();

				if(w==0&&h==0)break;
			int[][] map = new int[h][w];
			int[][] submap = new int[h][w];
			Mapnode[][] mapnode = new Mapnode[h][w];
			HashMap<Integer, LinkedList<int[]>> dp = new HashMap<Integer, LinkedList<int[]>>();

			int starty = -1;
			int startx = -1;
			int goaly = -1;
			int goalx = -1;

			int max = 0;

			for (int i = 0; i < h; i++) {
				for (int j = 0; j < w; j++) {
					mapnode[i][j] = new Mapnode(i, j);
					String str = sc.next();
					if (str.equals("S")) {
						map[i][j] = 20000;
						starty = i;
						startx = j;
						mapnode[i][j].name = "S";
					} else if (str.equals("G")) {
						mapnode[i][j].name = "G";
						map[i][j] = 20001;
						goaly = i;
						goalx = j;
					} else if (str.equals("."))
						map[i][j] = 0;
					else {
						map[i][j] = Integer.parseInt(str);
						int[] subsub = new int[2];
	
						if(!dp.containsKey(map[i][j])){
							LinkedList<int[]> ppp = new LinkedList<int[]>();						
							dp.put(map[i][j], ppp);
							
						}
						
						subsub[0] = i;
						subsub[1] = j;
						dp.get(map[i][j]).add(subsub);
						max = Math.max(map[i][j], max);

					}

				}

			}

			int[] subbb = new int[2];
			LinkedList<int[]> startstart = new LinkedList<int[]>();
			subbb[0] = starty;
			subbb[1] = startx;

			dp.put(0, startstart);
			dp.get(0).add(subbb);

			int[] subbb2 = new int[2];
			LinkedList<int[]> goalgoal = new LinkedList<int[]>();
			subbb2[0] = goaly;
			subbb2[1] = goalx;

			dp.put(max + 1, goalgoal);
			dp.get(max + 1).add(subbb2);

			Masuda[][] masu = new Masuda[max + 2][20000];

			for (int i = 0; i < max + 2; i++) {
				for (int j = 0; j < 20000; j++) {
					masu[i][j] = new Masuda();
				}
			}

			masu[0][0].y = dp.get(0).get(0)[0];
			masu[0][0].x = dp.get(0).get(0)[1];
			masu[0][0].time = true;


		/*	System.out.println(dp.get(1).size());
			System.out.println(dp.get(2).size());
			System.out.println(dp.get(3).size());
			System.out.println(dp.get(4).size());
			System.out.println(dp.get(5).size());
			*/
			for (int i = 1; i <= max + 1; i++) {
				for (int[] j : dp.get(i)) {					
					for (int k = 0; k < 20000; k++) {
						if (masu[i - 1][k].time) {
							Masuda mmm = masu[i - 1][k];
							int sumy = mmm.y < j[0] ? j[0] - mmm.y : mmm.y - j[0];
							int sumx = mmm.x < j[1] ? j[1] - mmm.x : mmm.x - j[1];
							int sum = sumy + sumx;
							if (k + sum < 20000) {
								masu[i][k + sum].y = j[0];
								masu[i][k + sum].x = j[1];
								masu[i][k + sum].time = true;
							}
						}
					}
				}

			}

			for (int i = 0; i < 20000; i++) {
				if (masu[max + 1][i].time) {
					System.out.println(i);
					break;
				}
			}
		/*	
			for(int i=0;i<=max+1;i++){
				for(int j=0;j<=100;j++){
					System.out.print(masu[i][j].time?" "+j:" F");	
					
				}
				System.out.println();	
			}
			*/
		}
	}

}

class Mapnode {
	int myy;
	int myx;
	int length = 20000;
	String name = "";
	boolean frag = false;
	ArrayList<Integer> listy = new ArrayList<Integer>();
	ArrayList<Integer> listx = new ArrayList<Integer>();
	ArrayList<Mapnode> queue = new ArrayList<Mapnode>();

	public Mapnode(int y, int x) {
		myy = y;
		myx = x;
	}
}

class Masuda {
	int y;
	int x;
	boolean time;

	public Masuda() {
		time = false;
	}
}