Problem:
JOI 国の買い物事情(Shopping in JOI Kingdom)

JOI 国にはN 個の町があり，それらの間はM 本の双方向に通行可能な道路で結ばれている．K 個の町にはショッピングモールがあり，国民は道路を通ってそれらの町のいずれかに行き買い物をする．

家の場所によっては，買い物に行くために長い距離を移動する必要があり，それは非常に不便である．国王はこの実情を把握するため，ショッピングモールのある町までの最短距離が家の場所によってどれだけ長くなりうるのかを調べることにした．家は道路の途中に建てられることもあるので(入力例1 の説明を参照)，この調査は非常に大変である．そこで国王は，優秀なプログラマーであるあなたに，調査を行うプログラムの作成を依頼した．

課題

道路の情報とショッピングモールのある町の情報が与えられるとき，ショッピングモールのある町からもっとも遠い道路上の点(端点も含む) までの距離を求めるプログラムを作成せよ．町の中を移動するのにかかる距離は無視してよい．

制限

2 ≤ N ≤ 3000     JOI 国の町の個数

1 ≤ M ≤ 100000 = 105     JOI 国の道路の本数

1 ≤ K ≤ N     ショッピングモールがある町の個数

1 ≤ li ≤ 1000     i 番目の道路の長さ

入力

標準入力から以下の入力を読み込め．

1 行目には整数N, M, K が空白区切りで書かれている．N はJOI 国の町の個数を，M はJOI 国の道路の本数を，i>K はショッピングモールがある町の個数をそれぞれ表す．町には1, 2, ..., N の番号がつけられている．

続くM 行は道路の情報を表す．i + 1 行目(1 ≤ i ≤ M) には整数ai, bi, li (1 ≤ ai ≤ N, 1 ≤ bi ≤ N, 1 ≤ li ≤ 1000) が空白区切りで書かれている．これは，i 本目の道路が町ai と町bi を結んでおり，長さがli であることを表す．道路の両端が同じ町であることはない．また，任意の2 つの町p, q に対し，pとq を結ぶ道路は2 本以上存在しない．どの町からどの町へもいくつかの道路をたどって行くことができる．

続くK 行はショッピングモールの情報を表す．i+M+1 行目(1 ≤ i ≤ K) には1 つの整数si (1 ≤ si ≤ N)が書かれている．これは町si にショッピングモールがあることを表す．s1, ..., sK の中に同じ値が2
回以上現れることはない．

出力

標準出力に，ショッピングモールのある町までの最短距離の最大値の小数点以下を四捨五入した整数1
つを出力せよ．

採点基準

採点用データのうち，配点の40% 分については，K = 1 を満たす．

入出力の例

入力例1

3 3 1
1 2 1
2 3 1
3 1 1
1

出力例1

2

入力例1 は次のような町を表す．道路の長さはすべて1 である．ショッピングモールは町1 にしかない．

ショッピングモールのある町までもっとも遠い点は，町2 と町3 を結ぶ道路上の，町2 から距離0.5 の位置にある点であり，ショッピングモールのある町までの距離は1.5 である．よって，それを四捨五入した値である2 を出力する．

入力例2

4 5 2
1 2 4
1 3 1
2 3 2
2 4 2
3 4 1
2
4

出力例2

3

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C (judge verdict: Accepted)

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define mem(x,y)		(x*)malloc(sizeof(x)*(y))
#define PI 3.14159265358979

int list_sort(const void* a,const void* b)
{
	if((*(int**)a)[0] > (*(int**)b)[0])
	{
		return 1;
	}
	else if((*(int**)a)[0] == (*(int**)b)[0])
	{
		if((*(int**)a)[1] > (*(int**)b)[1])
		{
			return 1;
		}
		else if((*(int**)a)[1] == (*(int**)b)[1])
		{
			return 0;
		}
	}
	return -1;
}

void dijkstra(int** list,int*** road,int* score,int m,int n,int s)
{
	int len;
	if(s == (n-1))
	{
		len = road[0]+m-road[s];
	}
	else
	{
		len = road[s+1]-road[s];
	}
	int i;
	for(i = 0;i < len;i++)
	{
		int sc = score[road[s][i][1]];
		if(sc > score[s]+road[s][i][2] || sc == -1)
		{
			score[road[s][i][1]] = score[s]+road[s][i][2];
			dijkstra(list,road,score,m,n,road[s][i][1]);
		}
		else if(sc < score[s]-road[s][i][2])
		{
			score[s] = sc+road[s][i][2];
			i = -1;
			continue;
		}
	}
}

int main()
{
	int m,n,k;
	int** list;
	int*** road;
	int* score;
	int i,j;
	double longest;
	scanf("%d %d %d",&n,&m,&k);
	score = mem(int,n);
	road = mem(int**,n);
	for(i = 0;i < n;i++)
	{
		score[i] = -1;
	}
	list = mem(int*,2*m);
	for(i = 0;i < m;i++)
	{
		list[i] = mem(int,3);
		list[i+m] = mem(int,3);
		scanf("%d %d %d",&list[i][0],&list[i][1],&list[i][2]);
		list[i+m][0] = --list[i][1];
		list[i+m][1] = --list[i][0];
		list[i+m][2] = list[i][2];
	}
	qsort(list,m*2,sizeof(int*),list_sort);
	j = 0;
	for(i = 0;i < n;i++)
	{
		road[i] = list+j;
		while(j < m*2 && list[j][0] == i)j++;
	}
	for(i = 0;i < k;i++)
	{
		int s;
		scanf("%d",&s);
		score[s-1] = 0;
	}
	for(i = 0;i < n;i++)
	{
		if(score[i] != -1)
			dijkstra(list,road,score,2*m,n,i);
	}
	longest = 0;
	for(i = 0;i < m*2;i++)
	{
		int val = score[list[i][0]]+score[list[i][1]]+list[i][2];
		if(val > longest*2)
		{
			longest = (double)val/2.0;
		}
	}
	int num = floor(longest+0.5);
	printf("%d\n",num);
	return 0;
}