AOJ0562 Shopping in JOI Kingdom

問題リンク Shopping in JOI Kingdom

  • 解法

ある1本の道に着目し、この道の上でショッピングモールからもっとも離れている場所はどこかを考えるのが方針です。そのためには、道の両端にある町それぞれについてショッピングモールとの最短距離が求まっていないと解けないです。これを求めるにはK回ダイクストラすればいいでしょう。
道の両端の町のショッピングモールとの最短距離がd[s], d[t]、道の長さがLのときを考えます。d[s] <= d[t]とします。
もしd[s]==d[t]なら話は簡単で、最遠距離は道の真ん中です。つまり、d[s] + L/2が最遠距離となります。
そうでない場合、d[s]にd[t]との差分を足せば同じ状況を作り出せます。つまり、difを dif = d[t] - d[s] とすると、
d[s]: d[s]+dif
d[t]: d[t]
L: L-dif
という状態の道と同じことになり、最遠距離は d[s]+dif+(L-dif)/2 と求めることができます。
これをM本全ての道についてチェックすれば解けます。

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

//Shopping in JOI Kingdom
public class AOJ0562 {

	int n, m, k, INF = 1<<29;
	List<E>[] adj;
	int[] d;
	
	class E{
		int t, c;
		public E(int t, int c) {
			this.t = t;
			this.c = c;
		}
	}
	
	void dijkstra(int x){
		d[x] = 0;
		PriorityQueue<Integer> q = new PriorityQueue<Integer>(n, new Comparator<Integer>() {
			public int compare(Integer o1, Integer o2) {
				return d[o1]-d[o2];
			}
		});
		q.add(x);
		while(!q.isEmpty()){
			int v = q.poll();
			for(E e:adj[v]){
				int w = d[v]+e.c;
				if(w<d[e.t]){
					q.remove(e.t); d[e.t] = w; q.add(e.t);
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	void run(){
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt(); m = sc.nextInt(); k = sc.nextInt();
		adj = new List[n];
		for(int i=0;i<n;i++)adj[i]=new ArrayList<E>();
		d = new int[n];
		Arrays.fill(d, INF);
		while(m--!=0){
			int s = sc.nextInt()-1, t = sc.nextInt()-1, c = sc.nextInt();
			adj[s].add(new E(t, c)); adj[t].add(new E(s, c));
		}
		while(k--!=0)dijkstra(sc.nextInt()-1);
		double res = 0;
		for(int i=0;i<n;i++)for(E e:adj[i]){
			int dif = Math.abs(d[i]-d[e.t]);
			if(d[i]<d[e.t])res = Math.max(res, d[i]+dif+(e.c-dif)/2.0);
			else res = Math.max(res, d[e.t]+dif+(e.c-dif)/2.0);
		}
		System.out.printf("%.0f\n", res);
	}
	
	public static void main(String[] args) {
		new AOJ0562().run();
	}
}