思考する三角形▽

プログラミング初心者によるAtCoder解答解説

C - 器物損壊!高橋君

コメント歓迎です。

今回も幅優先探索の応用問題です。

0-1-BFSと呼ばれている手法のようです。

タイトルの勢いが結構好きです。


方針

今回の問題で初めてdequeというものを使いました。


dequeは普通のqueueとは違い、先頭にも最後尾にもpushできます。


今回の使い方としては優先度の高いものは先頭にpushし、
優先度が低いものは最後尾にpushします。


そうすることによって優先度が高いものからpopされ、処理が進むことになります。


迷路は通路('.', 's', 'g')か壁('#')の二種類しかなく、通路を優先して処理しています。


変数scoreの値は壁を一度壊さないと進めないマスは"1"、二度なら"2"、三度なら"3"といった具合になります。


下に例を示します。


迷路

s . . . . . . . . .
# # # # # # # # # .
# . . . . . . . # .
# . . # # # # . # .
# # . . . . # . # .
# # # # # . # . # .
g # # . # . # . # .
# # # . # . # . # .
# # # . # . # . # .
# . . . . . # . . .


処理後のscore

0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 0
1 0 0 0 0 0 0 0 1 0
1 0 0 1 1 1 1 0 1 0
2 1 0 0 0 0 1 0 1 0
3 2 1 1 1 0 1 0 1 0
2 2 1 0 1 0 1 0 1 0
3 2 1 0 1 0 1 0 1 0
2 1 1 0 1 0 1 0 1 0
1 0 0 0 0 0 1 0 0 0


ゴールマスのscoreが2以下であれば壁を壊す回数が2回以下でたどり着けることになります。



コード(AC)

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
 
// 宣言
char maze[500][500]; // 迷路データ
int H; // 高さ
int W; // 幅
  
int sh, sw; // スタート地点
int gh, gw; // ゴール地点
vector< vector<int> > score(500, vector<int> (500, 100)); // 手数
bool visited[500][500]; // 訪問履歴
const int dh[] = {1, -1, 0, 0};
const int dw[] = {0, 0, 1, -1};
  
// 幅優先探索
void bfs(int i, int j) {
  // キューを準備
  deque<pair<int,int> > Q;
  // スタート地点のスコアを0にセット
  score[i][j] = 0;
  // スタート地点の座標をキューにプッシュ
  Q.push_back(make_pair(i, j));
  // キューが空になるまで処理を実行
  while(!Q.empty()) {
    // 探索の起点となる座標を記憶してからポップ
    pair<int,int> q = Q.front();
    Q.pop_front();
    int h = q.first;
    int w = q.second;
    // 起点を元に座標を移動
    for (int k = 0; k < 4; k++) {
      int nh = h + dh[k];
      int nw = w + dw[k];
      // 移動先が迷路の範囲外なら処理をスキップ
      if (nh < 0 || nh >= H || nw < 0 || nw >= W) {
        continue;
      }
      // 移動先が壁ならdequeの最後尾にプッシュ
      if (score[nh][nw] > (score[h][w] + 1) && maze[nh][nw] == '#') {
        Q.push_back(make_pair(nh, nw));
        // 移動先のスコアを起点のスコア+1にする
        score[nh][nw] = score[h][w] + 1;
      }
      // そうでなければdequeの先頭にプッシュ
      if (score [nh][nw] > score[h][w] && maze[nh][nw] != '#'){
        Q.push_front(make_pair(nh, nw));
        // 移動先のスコアを起点のスコアと同じにする
        score[nh][nw] = score[h][w];
      }
    }
  }
}
  
int main() {
  // 入力
  cin >> H >> W;
  // 迷路データ
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      cin >> maze[i][j];
      // スタート地点を記録
      if (maze[i][j] == 's') {
        sh = i;
        sw = j;
      }
      // ゴール地点を記録
      if (maze[i][j] == 'g') {
        gh = i;
        gw = j;
      }
    }
  }
  
  // 幅優先探索
  bfs(sh, sw);
  
  // 出力
  cout << (score[gh][gw] <= 2 ? "YES" : "NO") << endl;
  return 0;
}