AOJ2200 Mr. Rito Post Office

問題リンク Mr. Rito Post Office

  • 解法

ワーシャルフロイドで下ごしらえしてからDPで解きました。
まず、陸路のみでの移動、海路のみでの移動それぞれについて全頂点間最短距離をワーシャルフロイドで求めます。
次に、以下のようなDPを考えます。
dp[i][j]: 頂点jに船がある状態でi番目の配達先に訪れるときの最短コスト
最終的にdp[R][j]のうちの最小値が答えになります。
漸化式は次のようなノリです。
pre: i-1番目の配達先
nx: i番目の配達先
とします。
if(j!=k) //船の場所が異なるとき、pre-(陸路)-> k -(海路)-> j -(陸路)-> nx と移動する
dp[i][j] = min { dp[i-1][k] + wf_land[pre][k] + wf_sea[k][j] + wf_land[j][nx] }
else //船の場所は同じなので、陸路を伝う
dp[i][j] = min { dp[i-1][k] + wf_land[pre][nx] }

  • ソース
import java.util.Arrays;
import java.util.Scanner;

//Mr. Rito Post Office
public class AOJ2200 {

	void run(){
		Scanner sc = new Scanner(System.in);
		int INF = 1<<28;
		for(;;){
			int n = sc.nextInt(), m = sc.nextInt();
			if((n|m)==0)break;
			int[][] wf1 = new int[n][n], wf2 = new int[n][n];
			for(int i=0;i<n;i++)for(int j=0;j<n;j++){
				wf1[i][j] = wf2[i][j] = INF;
			}
			for(int i=0;i<n;i++)wf1[i][i] = wf2[i][i] = 0;
			while(m--!=0){
				int s = sc.nextInt()-1, t = sc.nextInt()-1, cost = sc.nextInt();
				String str = sc.next();
				if("L".equals(str))wf1[s][t] = wf1[t][s] = Math.min(wf1[s][t], cost);
				else wf2[s][t] = wf2[t][s] = Math.min(wf2[s][t], cost);
			}
			for(int k=0;k<n;k++)for(int i=0;i<n;i++)for(int j=0;j<n;j++){
				wf1[i][j] = Math.min(wf1[i][j], wf1[i][k]+wf1[k][j]);
				wf2[i][j] = Math.min(wf2[i][j], wf2[i][k]+wf2[k][j]);
			}
			int R = sc.nextInt();
			int[][] dp = new int[2][n];
			Arrays.fill(dp[0], INF);
			int X = 1;
			int pre = sc.nextInt()-1;
			dp[0][pre] = 0;
			for(;--R!=0;X=1-X){
				int k = sc.nextInt()-1;
				Arrays.fill(dp[X], INF);
				for(int i=0;i<n;i++)for(int j=0;j<n;j++){
					if(i!=j)
						dp[X][i] = Math.min(dp[X][i], dp[1-X][j]+wf1[pre][j]+wf2[j][i]+wf1[i][k]);
					else
						dp[X][i] = Math.min(dp[X][i], dp[1-X][j]+wf1[pre][k]);
				}
				pre = k;
			}
			int res = INF;
			for(int i=0;i<n;i++)res = Math.min(res, dp[1-X][i]);
			System.out.println(res);
		}
	}
	
	public static void main(String[] args) {
		new AOJ2200().run();
	}
}