RUPC D, AOJ-2284: 伝説の剣 (The Legendary Sword)
問題概要
二次元ボード(W,H<100)が与えられる。各マスには数字が入っていたりする。スタートから開始して、数字の1から順に触れていく。ゴールまで移動する最短距離を求める問題。
考えたこと
- また随分と入力が読み取り辛いですなあ。
- こんなん毎回幅優先すればいいでしょう。基本的には数字の大きいところからDP。
- TLE。
- 幅優先するまでもなくマンハッタン距離でいいのか。修正。無事AC。
- 今考えると別に後ろからDPする必要は無くて、前から順にやればよかった。
本番で通ったコード
#include <cstdio> #include <iostream> #include <cstring> #include <sstream> #include <vector> #include <algorithm> using namespace std; const int MAX_W = 100; const int MAX_N = 100*100 + 2; const int INF = 1<<29; const int START = MAX_N - 2; const int GOAL = MAX_N - 1; const int dy[] = {0, 0, 1, -1}; const int dx[] = {1, -1, 0, 0}; int W, H; int board[MAX_W][MAX_W + 1]; bool visited[MAX_W][MAX_W]; int dist[MAX_W][MAX_W]; vector< pair<int,int> > nums[MAX_N]; struct state{ int y, x, dist; }; int search(int y, int x, int goal){ int ans = INF; for(int i=0; i<(int)nums[goal].size(); i++){ int ty = nums[goal][i].first, tx = nums[goal][i].second; ans = min(ans, abs(y - ty) + abs(x - tx) + dist[ty][tx]); } return ans; } int solve(){ //最大値を探す int max_dig = 0, sy = -1, sx = -1; for(int i=0; i<H; i++){ for(int j=0; j<W; j++){ if(board[i][j] < START)max_dig = max(max_dig, board[i][j]); if(board[i][j] == START){ sy = i; sx = j; } } } //max_dig == 0の場合に注意(ただの幅優先) if(max_dig == 0){ return search(sy, sx, GOAL); } for(int i=max_dig; i>=0; i--){ for(int y=0; y<H; y++)for(int x=0; x<W; x++){ if(board[y][x] == (i > 0 ? i : START)){ dist[y][x] = search(y, x, (i==max_dig ? GOAL : i + 1)); } } } return dist[sy][sx]; } int to_int(string s){ stringstream ss(s); int x; ss >> x; return x; } int main(){ while(scanf("%d%d ",&W, &H), H){ memset(dist, 0, sizeof(dist)); for(int i=0; i<MAX_N; i++) nums[i].clear(); for(int i=0; i<H; i++){ for(int j=0; j<W; j++){ string str; cin >> str; if(str == "."){ board[i][j] = 0; } else if(str == "S"){ board[i][j] = START; nums[START].push_back(make_pair(i, j)); } else if(str == "G"){ board[i][j] = GOAL; nums[GOAL].push_back(make_pair(i, j)); } else{ board[i][j] = to_int(str); nums[board[i][j]].push_back(make_pair(i, j)); } } cin.ignore(); } printf("%d\n", solve()); } return 0; }