AOJ0230 Ninja Climbing

問題リンク Ninja Climbing

  • 解法

忍者の位置による幅優先探索です。コストは移動距離ではなく、ジャンプした回数です。
ビルの状態によって色々場合分けが必要なので、注意深く実装する必要がある厄介な問題だと思います。

  • ソース
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;

//Ninja Climbing
public class AOJ0230 {

	static int[][] dist;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(true){
			int n = sc.nextInt();
			if(n==0)break;
			int[][] a = new int[n][2];
			for(int i=0;i<2;i++)for(int j=0;j<n;j++)a[j][i]=sc.nextInt();
			dist = new int[n][2];
			for(int i=0;i<n;i++)Arrays.fill(dist[i], Integer.MAX_VALUE);
			dist[0][0] = dist[0][1] = 0;
			PriorityQueue<int[]> q = new PriorityQueue<int[]>(n, new Comparator<int[]>() {
				public int compare(int[] o1, int[] o2) {
					return dist[o1[0]][o1[1]]-dist[o2[0]][o2[1]];
				}
			});
			q.add(new int[]{0,0});
			q.add(new int[]{0,1});
			int ans = -1;
			while(!q.isEmpty()){
				int[] v = q.poll();
				int h = v[0];
				int w = v[1];
				if(h==n-1 && a[n-1][w]!=2){
					ans = dist[n-1][w];
					break;
				}
				if(a[h][w]==2){
					if(dist[h][w] < dist[h-1][w]){
						dist[h-1][w] = dist[h][w];
						q.add(new int[]{h-1,w});
					}
				}
				else if(a[h][w]==1){
					if(a[h+1][w]==1){
						if(dist[h][w] < dist[h+1][w]){
							dist[h+1][w] = dist[h][w];
							q.add(new int[]{h+1, w});
						}
					}
					else {
						int d = w==0?1:0;
						for(int k=0;k<3;k++){
							int nh = h + k;
							if(nh > n-1)break;
							if(dist[h][w]+1 < dist[nh][d]){
								dist[nh][d] = dist[h][w]+1;
								q.add(new int[]{nh,d});
							}
						}
					}
				}
				else{
					int d = w==0?1:0;
					for(int k=0;k<3;k++){
						int nh = h + k;
						if(nh > n-1)break;
						if(dist[h][w]+1 < dist[nh][d]){
							dist[nh][d] = dist[h][w]+1;
							q.add(new int[]{nh,d});
						}
					}
				}
			}
			System.out.println(ans==-1?"NA":ans);
		}
	}
}