AOJ : 2085 - Turn Left
問題概要
http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=2085
m 個の交差点の名前と位置が与えられます.
さらに, この m 個の交差点のどれか二つを結ぶ通りが n 本あります.
「直進」と「左折」のみを使って移動するとき, 交差点 src から交差点 dst まで行くのに, 最小で何回交差点を通る必要があるかを答える問題です.
ただし, スタートからゴールまでの移動距離は, 最短距離である必要があります.
アルゴリズム
交差点をノード, 通りをエッジとみなして, グラフを生成します.
あとは, 次の状態をもたせるクラスを作成し, ダイクストラ法で解きます.
- 現在の交差点の名前
- 現在向いている方向
- 今までの移動距離
- 今までに交差点を通った回数
グラフ生成が面倒ですが, それを作りさえすれば, あとは普通のダイクストラ法で解けます.
グラフは, 自分が処理しやすいように作りましょう.
プログラム
import java.util.*; import java.awt.Point; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(true){ int n = sc.nextInt(); int m = sc.nextInt(); if(n == 0 && m == 0) break; //各交差点の座標を記憶するマップ HashMap<String,Point> pmap = new HashMap<String,Point>(); for(int i=0;i<n;i++){ String name = sc.next(); Point p = new Point(sc.nextInt(),sc.nextInt()); pmap.put(name,p); } //交差点の東西南北の方向に, 他のどの交差点がつながっているかを記憶するマップ HashMap<String,ArrayList<String>> map = new HashMap<String,ArrayList<String>>(); for(String name : pmap.keySet()){ ArrayList<String> zeroList = new ArrayList<String>(); for(int i=0;i<4;i++) zeroList.add(null); map.put(name,zeroList); } for(int i=0;i<m;i++){ String s = sc.next(); String d = sc.next(); Point sp = pmap.get(s); Point dp = pmap.get(d); //交差点 s の東に交差点 d がある if(dp.x - sp.x > 0){ map.get(s).set(1,d); map.get(d).set(3,s); } //交差点 s の西に交差点 d がある else if(dp.x - sp.x < 0){ map.get(s).set(3,d); map.get(d).set(1,s); } //交差点 s の北に交差点 d がある else if(dp.y - sp.y > 0){ map.get(s).set(0,d); map.get(d).set(2,s); } //交差点 s の南に交差点 d がある else { map.get(s).set(2,d); map.get(d).set(0,s); } } String s = sc.next(); String d = sc.next(); PriorityQueue<State> open = new PriorityQueue<State>(); HashSet<State> closed = new HashSet<State>(); for(int i=0;i<4;i++){ open.add(new State(s,i,0,1)); } State ans = null; while(!open.isEmpty()){ State st = open.poll(); if(closed.contains(st)) continue; closed.add(st); if(st.name.equals(d)){ ans = st; break; } //直進 String next = map.get(st.name).get(st.d); if(next != null){ int dist = (int)pmap.get(st.name).distance(pmap.get(next)); open.add(new State(next,st.d,st.dist+dist,st.cost+1)); } //左折 int nd = (st.d + 3) % 4; //左折の方向 next = map.get(st.name).get(nd); if(next != null){ int dist = (int)pmap.get(st.name).distance(pmap.get(next)); open.add(new State(next,nd,st.dist+dist,st.cost+1)); } } System.out.println(ans == null ? "impossible" : ans.cost); } } } class State implements Comparable<State>{ String name; //交差点名 int d,dist,cost; //現在向いている方向,今まで歩いた距離,通った交差点の数 State(String name,int d,int dist,int cost){ this.name = name; this.d = d; this.dist = dist; this.cost = cost; } public int compareTo(State st){ if(dist < st.dist) return -1; else if(dist > st.dist) return 1; return cost - st.cost; } public boolean equals(Object o){ State st = (State)o; return name.equals(st.name) && d == st.d; } public int hashCode(){ return name.hashCode() + d; } }