AOJ2085 Turn Left
問題リンク Turn Left
- 概要
M個の交差点とN本の双方向道路がある。交差点にはそれぞれ名前Sがついており、座標(x, y)にある。
交差点srcとdestが与えられる。道路を走る際、右に曲がることはできない、Uターンもできない。この条件のもとで、srcからdestへ最短距離で向かう時、交差点を通過する最小回数を答えよ。たどり着けない場合"impossible"とせよ。
最初の移動はどの方向へ移動してもよい。出発するときのsrcや、到着したときのdestも通過したものと考えよ。
次のことが保証されている。
同じ座標に2つ以上の交差点が存在することは無い
端点が同じ道路は2本以上存在しない
道路の途中に別の交差点があるような道路は存在しない
srcとdestは異なる
2 <= M <= 1000
0 <= x, y <= 10000
S | <= 25 |
- 解法
ダイクストラです。(現在の交差点、直前の交差点)をノードにしたグラフを作ります。このノードに対して、[最短距離]と[最小通過回数]を覚えておきます。探索するノードは[最短距離]、[最小通過回数]の順に順位付けします。
右へ移動できないので、外積を使って判定します。[移動先が左側にある]かつ[移動先が直前の交差点でない]ならば、移動できます。
- ソース
import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Scanner; //Turn Left public class AOJ2085 { double EPS = 1e-10; int INF = 1<<29, M = 1000; int[] x, y; boolean ok(int pre, int v, int next){ int x1 = x[v]-x[pre], y1 = y[v]-y[pre], x2 = x[next]-x[pre], y2 = y[next]-y[pre]; return x1*y2-x2*y1>=0; } int[][] pass; double[][] d; @SuppressWarnings("unchecked") void run(){ Scanner sc = new Scanner(System.in); for(;;){ int m = sc.nextInt(), n = sc.nextInt(); if((m|n)==0)break; Map<String, Integer> ref = new HashMap<String, Integer>(); x = new int[m]; y = new int[m]; for(int i=0;i<m;i++){ ref.put(sc.next(), i); x[i] = sc.nextInt(); y[i] = sc.nextInt(); } double[][] dist = new double[m][m]; List<Integer>[] adj = new List[m]; for(int i=0;i<m;i++)adj[i]=new ArrayList<Integer>(); while(n--!=0){ int s = ref.get(sc.next()), t = ref.get(sc.next()); adj[s].add(t); adj[t].add(s); dist[s][t] = dist[t][s] = Math.sqrt((x[s]-x[t])*(x[s]-x[t])+(y[s]-y[t])*(y[s]-y[t])); } int s = ref.get(sc.next()), g = ref.get(sc.next()); d = new double[m][m]; for(double[]a:d)Arrays.fill(a, INF); pass = new int[m][m]; for(int[]a:pass)Arrays.fill(a, INF); PriorityQueue<Integer> q = new PriorityQueue<Integer>(m, new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { if(Math.abs(d[o1/M][o1%M]-d[o2/M][o2%M])<EPS)return pass[o1/M][o1%M]-pass[o2/M][o2%M]; return (int)Math.signum(d[o1/M][o1%M]-d[o2/M][o2%M]); } }); for(int v:adj[s]){ d[v][s] = dist[s][v]; pass[v][s] = 2; q.add(v*M+s); } int res = INF; while(!q.isEmpty()){ int a = q.poll(); int v = a/M, pre = a%M; if(v==g){ res = pass[v][pre]; break; } for(int k:adj[v]){ if(k==pre)continue; if(!ok(pre, v, k))continue; double w = d[v][pre] + dist[v][k]; int t = pass[v][pre]+1; if(Math.abs(w-d[k][v])<EPS&&t<pass[k][v]){ pass[k][v] = t; q.add(k*M+v); } else if(w<d[k][v]){ d[k][v] = w; pass[k][v] = t; q.add(k*M+v); } } } System.out.println(res==INF?"impossible":res); } } public static void main(String[] args) { new AOJ2085().run(); } }