arrows blog

解いた問題などを適当に書いていきます。

AOJ 1214 - Walking Ant

問題概要

H×Wの二次元グリッドがあり、グリッドは、障害物(0)、移動可能なマス(1)、スタート位置(2)、ゴール位置(3)、回復地点(4)で構成されている。蟻がスタート位置からライフポイント6の状態でスタートしライフポイントが0にならないようにゴール位置へ到達できる場合はその最短時間を求めよ。できない場合は-1を出力せよ。蟻は上下左右のマスに移動するために時間が1かかりライフポイントが1消費される。回復地点に到達した場合ライフポイントは6に回復する。

制約

  • H ≤ 8
  • W ≤ 8

解法

現在位置と残り体力を状態に持って、BFSをする。

コード

#include <bits/stdc++.h>
 
using namespace std;
 
#define MAX 10
#define INF 1e9
typedef pair<int,int> pii;
typedef pair<pii,int> piii;
 
int H,W,sx,sy,gx,gy;
int field[MAX][MAX];
const int dx[] = {-1,0,1,0};
const int dy[] = {0,-1,0,1};
 
bool inField(int x,int y){
  return 0 <= x && x < W && 0 <= y && y < H;
}
 
int bfs(){
  queue<piii> Q;
  Q.push(piii(pii(sx,sy),6));
  int d[MAX][MAX][7];
  fill(d[0][0],d[0][0]+MAX*MAX*7,INF);
  d[sy][sx][6] = 0;
   
  while(!Q.empty()){
    piii p = Q.front(); Q.pop();
    int x = p.first.first, y = p.first.second;
    int life = p.second;
 
    if(x == gx && y == gy){
      return d[y][x][life];
    }                                        
    if(life == 1) continue;
    for(int i = 0 ; i < 4 ; i++){
      int nx = x + dx[i];
      int ny = y + dy[i];
      if(!inField(nx,ny)) continue;
      if(field[ny][nx] == 0) continue;
      if(field[ny][nx] == 4){
        if(d[y][x][life] + 1 < d[ny][nx][6]){
          d[ny][nx][6] = d[y][x][life] + 1;
          Q.push(piii(pii(nx,ny),6));
        }
      }else{
        if(d[y][x][life] + 1 < d[ny][nx][life-1]){
          d[ny][nx][life-1] = d[y][x][life] + 1;
          Q.push(piii(pii(nx,ny),life-1));
        }
      }
    }    
  }
  return -1;
}
 
int main(){
  while(cin >> W >> H, W){
    for(int i = 0 ; i < H ; i++){
      for(int j = 0 ; j < W ; j++){
        cin >> field[i][j];
        if(field[i][j] == 2){
          sx = j; sy = i;
        }else if(field[i][j] == 3){
          gx = j; gy = i;
        }
      }
    }
    cout << bfs() << endl;
  }
  return 0;
}