https://www.acmicpc.net/problem/16509

 

16509번: 장군

오랜만에 휴가를 나온 호근이는 문득 동아리방에 있는 장기가 하고 싶어졌다. 하지만 장기를 오랫동안 하지 않은 탓인지 예전에는 잘 쓰던 상을 제대로 쓰는 것이 너무 힘들었다. 호근이를 위해

www.acmicpc.net

 

문제

오랜만에 휴가를 나온 호근이는 문득 동아리방에 있는 장기가 하고 싶어졌다. 하지만 장기를 오랫동안 하지 않은 탓인지 예전에는 잘 쓰던 상을 제대로 쓰는 것이 너무 힘들었다. 호근이를 위해 상을 어떻게 써야 할지 도와주자.

위 그림은 10×9 크기의 장기판을 나타내며, 상은 (5, 4)에, 왕은 (1, 4)에 자리 잡고 있는 기물이다. (0, 3)과 (2, 5)를 꼭짓점으로 하는 사각형과, (7, 3)과 (9, 5)를 꼭짓점으로 하는 사각형은 왕이 위치할 수 있는 궁성이라고 한다. 상은 위 그림과 같이 8가지 방법으로 움직일 수 있는데, 상, 하, 좌, 우로 한 칸을 이동한 후에 같은 방향 쪽 대각선으로 두 칸 이동한다.

만약 상이 이동하는 경로에 위 그림과 같이 다른 기물이 있다면 상은 그쪽으로 이동할 수 없다. 또한, 상이 장기판을 벗어날 수도 없다.

10×9 크기의 장기판 위에 상과 왕의 처음 위치가 주어졌을 때, 상이 왕에게 도달할 수 있는 최소 이동 횟수를 구하여라.

입력

첫 번째 줄에는 상의 위치를 의미하는 정수 R1, C1이 주어진다.

두 번째 줄에는 왕의 위치를 의미하는 정수 R2, C2가 주어진다. 장기판에서 Ri (0 ≤ Ri ≤ 9)는 행을, Ci (0 ≤ Ci ≤ 8)는 열을 의미한다.

왕은 항상 궁성에 자리 잡고 있으며, 상과 왕의 위치는 겹치지 않는다.

출력

상이 왕에게 도달할 수 있는 최소 이동 횟수를 출력한다. 만약 도달할 수 없다면 -1을 출력한다.

 

문제접근 및 풀이

- BFS알고리즘으로 해결하였다.

 

BFS 탐색 과정 중 유의점

- 상이 움직일 수 있는 8가지를 탐색한다.

- 이때 움직이는 경로 중에 기물(왕)이 있으면 해당 경로로 이동하지 못한다.

#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>
#define VMAX 1000
#define INF 987654321

using namespace std;

pair<int,int> from;
pair<int,int> to;

int dx[8] = {3,3,2,-2,-3,-3,-2,2};
int dy[8] = {2,-2,-3,-3,-2,2,3,3};

bool check(int x,int y,int i){
  int tx = to.first;
  int ty = to.second;
  if(i==0)
    if((tx==x+1&&ty==y)||(tx==x+2&&ty==y+1)) return false;
  if(i==1)
    if((tx==x+1&&ty==y)||(tx==x+2&&ty==y-1)) return false;
  if(i==2)
    if((tx==x&&ty==y-1)||(tx==x+1&&ty==y-2)) return false;
  if(i==3)
    if((tx==x&&ty==y-1)||(tx==x-1&&ty==y-2)) return false;
  if(i==4)
    if((tx==x-1&&ty==y)||(tx==x-2&&ty==y-1)) return false;
  if(i==5)
    if((tx==x-1&&ty==y)||(tx==x-2&&ty==y+1)) return false;
  if(i==6)
    if((tx==x&&ty==y+1)||(tx==x-1&&ty==y+2)) return false;
  if(i==7){
    if((tx==x&&ty==y+1)||(tx==x+1&&ty==y+2)) return false;
    }
  return true;
}
int bfs(){
  int v[10][9]={0};
  queue<pair<pair<int,int>,int>> q;
  q.push({{from.first, from.second}, 0});
  v[from.first][from.second] = 1;
  while(!q.empty()){
    int x = q.front().first.first;
    int y = q.front().first.second;
    int c = q.front().second;
    q.pop();
    if(x==to.first && y==to.second){
      return c;
    }
    for(int i=0; i<8; i++){
      int nx = x + dx[i];
      int ny = y + dy[i];
      if(nx>=0 && ny>=0 && nx < 10 && ny < 9 && v[nx][ny]==0){
        if(check(x,y,i)==true){
          //printf("x:%d, y:%d, c:%d, i:%d\n",x,y,c,i);
          v[nx][ny]=1;
          q.push({{nx,ny}, c+1});
        }
      }
    }

  }

  return -1;
}

int main(){
  cin >> from.first >> from.second;
  cin >> to.first >> to.second;

  cout << bfs();

  return 0;
}

 

느낀점

- 시뮬레이션 요소가 들어가 있어서 새롭게 다가온 BFS문제였다. 간단히 해결할 수 있을 거라고 생각해서 바로 코딩에 옮겼지만 8가지 경로에 대해 왕이 중간에 있는지 체크하는 것을 구현하느라 시간이 좀 걸렸다. 이 과정을 좀 정리한 후에 코딩했으면 더 순조롭게 풀렸을 것 같다.

'알고리즘 문제풀이' 카테고리의 다른 글

[백준] 20046번 Road Reconstruction c++  (0) 2021.08.30
[백준] 1799번 비숍 c++  (0) 2021.08.28
[백준] 14722번 우유 도시 c++  (0) 2021.08.26
[백준] 14719번 빗물 c++  (0) 2021.08.26
[백준] 14716번 현수막 c++  (0) 2021.08.26

+ Recent posts