Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

AOJ 0215 - Pachimon Creature

問題文 : パチモンクリーチャー

解法 : 最初に選ぶパチクリを決めると, 次に選ぶパチクリが決まっていく. このパチクリ同士の関係を線で結んでいくと, 必然的にグラフになっている.
ゆえに, この問題はグラフの最短経路を求める問題に帰着できる.
ここでは, たどる辺の本数が高々5本であるため, この最短経路を動的計画法で求めている.

コード :

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>

using namespace std;

typedef struct {
	int x, y;
} Point;

vector<Point> mon[5];
int dp[5][1024];

int dist(Point i, Point j)
{
	return (abs(i.x - j.x) + abs(i.y - j.y));
}

int main()
{
	static char str[1024][1024];
	int W, H;
	Point S, G;
	
	while (1){
		scanf("%d %d", &W, &H);
		
		if (W + H == 0){
			break;
		}
		
		for (int i = 0; i < H; i++){
			scanf("%s", str[i]);
		}
		
		for (int i = 0; i < 5; i++){
			mon[i].clear();
		}
		
		for (int i = 0; i < H; i++){
			for (int j = 0; j < W; j++){
				if (str[i][j] == 'S'){
					S.x = j;
					S.y = i;
				}
				if (str[i][j] == 'G'){
					G.x = j;
					G.y = i;
				}
				if (1 <= str[i][j] - '0' && str[i][j] - '0' <= 5){
					Point t;
					t.x = j;
					t.y = i;
					mon[str[i][j] - '0' - 1].push_back(t);
				}
			}
		}
		
		int acre = 1 << 30, adist = 1 << 30;
		for (int i = 0; i < 5; i++){
			for (int j = 0; j < mon[(i + 1) % 5].size(); j++){
				dp[(i + 1) % 5][j] = dist(S, mon[(i + 1) % 5][j]);
			}
			for (int j = i + 2; j < i + 5; j++){
				int t = j % 5;
				int s = (t + 4) % 5;
				for (int k = 0; k < mon[t].size(); k++){
					dp[t][k] = 1 << 30;
				}
				for (int k = 0; k < mon[t].size(); k++){
					for (int l = 0; l < mon[s].size(); l++){
						dp[t][k] = min(dp[t][k], dp[s][l] + dist(mon[s][l], mon[t][k]));
					}
				}
			}
			int a = 1 << 30;
			for (int j = 0; j < mon[(i + 4) % 5].size(); j++){
				a = min(a, dp[(i + 4) % 5][j] + dist(mon[(i + 4) % 5][j], G));
			}
			if (a < adist){
				adist = a;
				acre = i + 1;
			}
		}
		if (acre != 1 << 30){
			printf("%d %d\n", acre, adist);
		}
		else {
			printf("NA\n");
		}
	}
	
	return (0);
}