AOJ2135 Reverse a Road

問題リンク Reverse a Road

  • 概要

1〜Nまでの番号がついた街と、M本の有向路(番号1〜M)がある。街SからTまでの最短距離を求めよ。
ただし、M本の辺のうち1本だけ向きを逆向きにすることができる。最短距離を得るために変えた辺の番号も答えよ。そのような辺が複数ある場合は最も番号が小さいものを答えよ。辺を逆向きにせずに最短距離が得られた場合は番号として0を答えよ。

  • 解法

愚直に全探索して解きました。
逆向きにする辺を全て選び、その都度幅優先探索をします。幅優先探索中、最短距離を更新できないことがわかったら探索を打ち切ります。
もっと賢い工夫を考えなければ解けないと思っていましたが、これで通ってしまいました。

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

//Reverse a Road
public class AOJ2135 {

	class E{
		int id, t;
		public E(int id, int t) {
			this.id = id;
			this.t = t;
		}
	}
	
	@SuppressWarnings("unchecked")
	void run(){
		Scanner sc = new Scanner(System.in);
		int INF = 1<<29;
		int[] d = new int[1001];
		int[][] e = new int[10001][2];
		List<E>[] adj = new List[1001];
		for(;;){
			int n = sc.nextInt();
			if(n==0)break;
			for(int i=1;i<=n;i++)adj[i]=new ArrayList<E>();
			int S = sc.nextInt(), T = sc.nextInt(), m = sc.nextInt();
			for(int i=1;i<=m;i++){
				int s = sc.nextInt(), t = sc.nextInt();
				adj[s].add(new E(i, t));
				e[i][0] = s; e[i][1] = t;
			}
			Arrays.fill(d, INF);
			d[S] = 0;
			Queue<Integer> q = new LinkedList<Integer>();
			q.add(S);
			while(!q.isEmpty()){
				int v = q.poll();
				for(E r:adj[v])if(d[r.t]==INF){
					d[r.t] = d[v]+1; q.add(r.t);
				}
			}
			int res = d[T], ID = 0;
			for(int i=1;i<=m;i++){
				Arrays.fill(d, INF);
				d[S] = 0;
				q = new LinkedList<Integer>();
				q.add(S);
				int rs = e[i][1], rt = e[i][0];
				while(!q.isEmpty()){
					int v = q.poll();
					if(res<=d[v])break;
					for(E r:adj[v])if(r.id!=i&&d[r.t]==INF){
						d[r.t] = d[v]+1; q.add(r.t);
					}
					if(v==rs&&d[rt]==INF){
						d[rt] = d[v]+1; q.add(rt);
					}
				}
				if(d[T]<res){
					res = d[T]; ID = i;
				}
			}
			System.out.println(res+" "+ID);
		}
	}
	
	public static void main(String[] args) {
		new AOJ2135().run();
	}
}