AOJ1319 Driving an Icosahedral Rover

問題リンク Driving an Icosahedral Rover

  • 概要

20面体を点(0, 0)に、"0"を接地させ"5"が北側になるように置く。1ステップに3方向へ転がすことができる。点(x, y)に数字nが接地するように動かすための最小ステップ数を答えよ。nが接地さえしていれば方向は問わない。答えは100ステップを超えないことが保証されている。

  • 解法

図工ゲーです。
市販の20面体を買うか、問題の20面体の展開図を切り取って工作するかして、20面体を手に入れます。
20面体は、接地している数値20通り × 3方向の 60通りの状態を持ちます。
状態に番号付けをして、転がした時の状態遷移を何とか作り出します。
この作業さえ乗り越えられれば後は楽で、プログラムの最初に100ステップ分の幅優先探索をかけ、テストケース毎にO(1)で答えます。
疲れました。

  • ソース
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

//Driving an Icosahedral Rover
public class AOJ1319 {

	int[][] move = {
			{5, 13, 15},
			{14, 16, 3},
			{17, 4, 12},
			
			{20, 8, 1},
			{6, 2, 18},
			{0, 19, 7},
			
			{4, 22, 11},
			{23, 9, 5},
			{10, 3, 21},
			
			{12, 7, 24},
			{8, 25, 13},
			{26, 14, 6},
			
			{9, 28, 2},
			{29, 0, 10},
			{1, 11, 27},
			
			{32, 34, 0},
			{35, 1, 30},
			{2, 31, 33},
			
			{34, 37, 4},
			{38, 5, 35},
			{3, 33, 36},
			
			{37, 40, 8},
			{41, 6, 38},
			{7, 36, 39},
			
			{40, 43, 9},
			{44, 10, 41},
			{11, 39, 42},
			
			{43, 32, 14},
			{30, 12, 44},
			{13, 42, 31},
			
			{28, 46, 16},
			{47, 17, 29},
			{15, 27, 45},
			
			{50, 20, 17},
			{18, 15, 48},
			{16, 49, 19},
			
			{53, 23, 20},
			{21, 18, 51},
			{19, 52, 22},
			
			{56, 26, 23},
			{24, 21, 54},
			{22, 55, 25},
			
			{59, 29, 26},
			{27, 24, 57},
			{25, 58, 28},
			
			{58, 50, 32},
			{48, 30, 59},
			{31, 57, 49},
			
			{46, 53, 34},
			{51, 35, 47},
			{33, 45, 52},
			
			{49, 56, 37},
			{54, 38, 50},
			{36, 48, 55},
			
			{52, 59, 40},
			{57, 41, 53},
			{39, 51, 58},
			
			{55, 47, 43},
			{45, 44, 56},
			{42, 54, 46}
	};
	
	void run(){
		Scanner sc = new Scanner(System.in);
		int[][][] d = new int[201][201][60];
		for(int i=0;i<201;i++)for(int j=0;j<201;j++)for(int k=0;k<60;k++)d[i][j][k] = 150;
		d[100][100][0] = 0;
		Queue<int[]> q = new LinkedList<int[]>();
		q.add(new int[]{100, 100, 0});
		while(!q.isEmpty()){
			int[] V = q.poll();
			int x = V[0], y = V[1], s = V[2];
			if(d[x][y][s]==100)break;
			int nx = x+1, ny = y, ns = ((x+y)&1)==0?move[s][0]:move[s][1];
			if(0<=nx&&nx<=200&&0<=ny&&ny<=200&&d[x][y][s]+1 < d[nx][ny][ns]){
				d[nx][ny][ns] = d[x][y][s]+1; q.add(new int[]{nx, ny, ns});
			}
			nx = x-1; ny = y; ns = ((x+y)&1)==0?move[s][1]:move[s][0];
			if(0<=nx&&nx<=200&&0<=ny&&ny<=200&&d[x][y][s]+1 < d[nx][ny][ns]){
				d[nx][ny][ns] = d[x][y][s]+1; q.add(new int[]{nx, ny, ns});
			}
			nx = x; ny = ((x+y)&1)==0?(y+1):(y-1); ns = move[s][2];
			if(0<=nx&&nx<=200&&0<=ny&&ny<=200&&d[x][y][s]+1 < d[nx][ny][ns]){
				d[nx][ny][ns] = d[x][y][s]+1; q.add(new int[]{nx, ny, ns});
			}
		}
		for(;;){
			int x = sc.nextInt(), y = sc.nextInt(), N = sc.nextInt();
			if((x|y|N)==0)break;
			x+=100; y+=100;
			int k = 3*N;
			System.out.println(Math.min(d[x][y][k], Math.min(d[x][y][k+1], d[x][y][k+2])));
		}
	}
	
	public static void main(String[] args) {
		new AOJ1319().run();
	}
}