반응형

문제 링크: https://www.acmicpc.net/problem/1938

 

1938번: 통나무 옮기기

첫째 줄에 주어진 평지의 한 변의 길이 N이 주어진다. (4 ≤ N ≤ 50) 주어진다. 이어서 그 지형의 정보가 0, 1, B, E로 이루어진 문자열로 주어진다. 한 줄에 입력되는 문자열의 길이는 N이며 입력 문

www.acmicpc.net

<문제 풀이> BFS 알고리즘

 

이 문제는 통나무의 중심 좌표를 가지고 목적지까지 최단거리로 이동하는 BFS를 구현하면 됩니다.

 

통나무는 현재 자신이 있는 좌표에서 BFS로 다음 좌표로 이동할 때 아래 두 가지 동작을 합니다.

1. 현재 좌표에 있는 통나무의 방향을 유지한 채로 4방향으로 이동한다.

2. 현재 좌표에 있는 통나무를 회전한 상태로 다음 좌표로 이동한다.

 

통나무의 중심 좌표를 (x,y)라고 할 때 수평 방향 통나무, 수직 방향 통나무 각각을 아래와 같이 표현할 수 있습니다.

수평 방향 통나무 (x, y - 1) (x, y) (x, y + 1)
수직 방향 통나무 (x -1, y) (x, y) (x + 1, y)

 

다음 좌표로 이동할 때 위 세 좌표가 '1'을 만나는지, 배열을 벗어나는지 판단해 주면 됩니다.

회전할 때는 중심 좌표를 기준으로 8방향을 확인하면 됩니다.

 

방문 체크는 (x, y)의 좌표를 수평 또는 수직 방향으로 방문했는지 판단하기 위해서 3차원 배열을 사용합니다.

visited[x][y][k]

=> (x, y)의 좌표를 k 방향 통나무를 가지고 방문한 적이 있는가?

=> k =0 이면 수평 방향, k = 1이면 수직 방향입니다.

 

 

<C++소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <queue>
using namespace std;
 
#define X first
#define Y second
 
class Bar {
public:
    int x, y, state;
    void setBar(int x, int y, int state) {
        this->= x;
        this->= y;
        this->state = state;
    }
    bool operator==(const Bar &bar) {
        if (this->== bar.x && this->== bar.y && this->state == bar.state) return true;
        else return false;
    }
};
 
Bar start, dest;
 
char board[50][50];
int visited[50][50][2]; // [i][j][0] = 수평, [i][j][1] = 수직, Bar의 가운데 좌표를 기준으로 방문체크
int n;
const int dx[4= {001-1};
const int dy[4= {1-100};
 
// Bar의 수평(0), 수직(1) 상태 리턴
int getState(vector<pair<intint > > bar) {
    if (bar[0].X - bar[1].X == 0return 0//연속된 2개의 B의 X 좌표가 같으면 수평
    else return 1// 그렇지 않으면 수직
}
 
void init() {
    for (int i = 0; i < 50; i++) {
        for (int j = 0; j < 50; j++) {
            for(int k=0; k<2; k++){
                visited[i][j][k] = -1;
            }
        }
    }
}
 
bool check(int x, int y) {
    return !(x < 0 || y < 0 || x >= n || y >= n || board[x][y] == '1');
}
 
void bfs() {
    queue<Bar> Q;
    Q.push({ start.x, start.y, start.state });
    visited[start.x][start.y][start.state] = 0;
 
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        if (cur == dest) {
            return;
        }
        if (cur.state == 0) { // 수평으로 이동
            for (int dir = 0; dir < 4; dir++) { // 4방향 이동
                int nx = cur.x + dx[dir];
                int ny = cur.y + dy[dir];
                if (!check(nx, ny - 1|| !check(nx, ny) || !check(nx, ny + 1|| visited[nx][ny][cur.state] != -1continue;
                Q.push({ nx, ny, cur.state });
                visited[nx][ny][cur.state] = visited[cur.x][cur.y][cur.state] + 1;
            }
            //수직방향으로 회전
            if (!check(cur.x - 1, cur.y) || !check(cur.x, cur.y) || !check(cur.x + 1, cur.y) || visited[cur.x][cur.y][!cur.state] != -1continue;
            if (!check(cur.x - 1, cur.y - 1|| !check(cur.x - 1, cur.y + 1|| !check(cur.x + 1, cur.y - 1|| !check(cur.x + 1, cur.y + 1))continue;
            Q.push({ cur.x, cur.y, !cur.state });
            visited[cur.x][cur.y][!cur.state] = visited[cur.x][cur.y][cur.state] + 1;
 
        }
        else { // 수직으로 이동
            for (int dir = 0; dir < 4; dir++) { // 4방향 이동
                int nx = cur.x + dx[dir];
                int ny = cur.y + dy[dir];
                if (!check(nx - 1, ny) || !check(nx, ny) || !check(nx + 1, ny) || visited[nx][ny][cur.state] != -1continue;
                Q.push({ nx, ny, cur.state });
                visited[nx][ny][cur.state] = visited[cur.x][cur.y][cur.state] + 1;
            }
            //수평방향으로 회전
            if (!check(cur.x, cur.y - 1|| !check(cur.x, cur.y) || !check(cur.x, cur.y + 1|| visited[cur.x][cur.y][!cur.state] != -1continue;
            if (!check(cur.x - 1, cur.y - 1|| !check(cur.x - 1, cur.y + 1|| !check(cur.x + 1, cur.y - 1|| !check(cur.x + 1, cur.y + 1))continue;
            Q.push({ cur.x, cur.y, !cur.state });
            visited[cur.x][cur.y][!cur.state] = visited[cur.x][cur.y][cur.state] + 1;
        }
    }
}
 
void input() {
    cin >> n;
    vector<pair<intint> > S, E;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> board[i][j];
            if (board[i][j] == 'B') S.push_back({ i, j });
            else if (board[i][j] == 'E')E.push_back({ i, j });
        }
    }
    start.setBar(S[1].X, S[1].Y, getState(S));
    dest.setBar(E[1].X, E[1].Y, getState(E));
}
void solve() {
    init();
    input();
    bfs();
    int ans = visited[dest.x][dest.y][dest.state];
    if (ans == -1cout << '0';
    else cout << ans;
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
 
    solve();
 
    return 0;
}
cs
 

 

반응형

+ Recent posts