반응형

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

 

3055번: 탈출

사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제

www.acmicpc.net

<문제 풀이> BFS, 최단거리
이문제는 모든 물에 대해서(물을 모두 큐에 담으면 됨) BFS로 물에서 모든 정점까지의 최단 거리를 구하고, 고슴 도치에 대해서 똑같이 BFS를 진행하면서 물 보다 더 최단 거리로 이동할 수 있는 경우만 큐에 담으면 됩니다.

 

주의할 점은 입력으로 물이 없을 수도 있습니다(물이 없으면 물의 visited 최단 거리 배열 값은 -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
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
 
#define X first
#define Y second
 
int R, C;
char board[50][50];
int visitedW[50][50];
int visitedS[50][50];
const int dx[4= { 001-1 };
const int dy[4= { 1-100 };
 
void wBFS() {
    queue<pair<intint> > Q;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            if (board[i][j] == '*') {
                Q.push({ i, j });
                visitedW[i][j] = 0;
            }
            }
    }
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int dir = 0; dir < 4; dir++) {
            int nx = cur.X + dx[dir];
            int ny = cur.Y + dy[dir];
            if (nx < 0 || ny < 0 || nx >= R || ny >= C)continue;
            if (board[nx][ny] == 'D' || board[nx][ny] == 'X'continue;
            if (visitedW[nx][ny] != -1)continue;
            Q.push({ nx, ny });
            visitedW[nx][ny] = visitedW[cur.X][cur.Y] + 1;
        }
    }
}
 
int sBFS() {
    int ret = -1;
    queue<pair<intint> > Q;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            if (board[i][j] == 'S') {
                Q.push({ i, j });
                visitedS[i][j] = 0;
            }
        }
    }
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int dir = 0; dir < 4; dir++) {
            int nx = cur.X + dx[dir];
            int ny = cur.Y + dy[dir];
            if (nx < 0 || ny < 0 || nx >= R || ny >= C)continue;
            if (board[nx][ny] == 'X'continue;
            if (visitedS[nx][ny] != -1)continue;
            if (board[nx][ny] != 'D' && visitedW[nx][ny] != -1 && visitedS[cur.X][cur.Y] + 1 >= visitedW[nx][ny])continue//물 보다 늦게 도착하면 무시
            Q.push({ nx, ny });
            visitedS[nx][ny] = visitedS[cur.X][cur.Y] + 1;
            if (board[nx][ny] == 'D') {
                return visitedS[nx][ny];
            }
        }
    }
    return ret;
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> R >> C;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            cin >> board[i][j];
        }
    }
    fill(&visitedW[0][0], &visitedW[49][50], -1);
    fill(&visitedS[0][0], &visitedS[49][50], -1);
    wBFS();
    int res = sBFS();
    if (res == -1cout << "KAKTUS";
    else cout << res;
    return 0;
}
cs

 

반응형
반응형

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

 

16946번: 벽 부수고 이동하기 4

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이

www.acmicpc.net

<문제 풀이>

각각의 벽에 대해서 BFS를 호출하면 벽 찾는데 O(N * M), BFS 호출하는데 O(N + M) 이므로 총 O( (N+M) * N*M )이 걸리게 된다.

 

벽을 부수었을 때 이동할 수 있는 곳은 벽을 기준으로 상하좌우의 0으로 이루어진 영역들이므로 0에 대해서 BFS를 1회 호출해서 영역을 구하고, 각 벽에 대해서 상하좌우 영역의 크기만 계산하면 O(N * M)에 해결할 수 있다.

 

<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
#include<iostream>
#include<queue>
#include<utility>
using namespace std;
 
#define X first
#define Y second
 
int N, M;
int board[1000][1000];
int visited[1000][1000];
int res[1000][1000];
int connected[1000001];
bool useC[1000001];
const int dx[4= { 001-1 };
const int dy[4= { 1-100 };
void bfs() {
    int flag = 1;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (board[i][j] || visited[i][j]) continue;
            queue<pair<intint> > Q;
            Q.push({ i, j });
            visited[i][j] = flag;
            int cnt = 1;
            while (!Q.empty()) {
                auto cur = Q.front(); Q.pop();
                for (int dir = 0; dir < 4; dir++) {
                    int nx = cur.X + dx[dir];
                    int ny = cur.Y + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                    if (board[nx][ny] || visited[nx][ny])continue;
                    Q.push({ nx, ny });
                    visited[nx][ny] = flag;
                    cnt++;
                }    
            }
            connected[flag] = cnt;
            flag++;
            
        }
    }
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            char c; cin >> c;
            board[i][j] = c - '0';
        }
    }
    bfs();
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (board[i][j] == 1) {
                res[i][j] = 1;
                for (int dir = 0; dir < 4; dir++) {
                    int nx = i + dx[dir];
                    int ny = j + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                    if (board[nx][ny] || useC[visited[nx][ny]]) continue;
                    useC[visited[nx][ny]] = true;
                    res[i][j] = (res[i][j] + connected[visited[nx][ny]]) % 10;
                }
                for (int dir = 0; dir < 4; dir++) {
                    int nx = i + dx[dir];
                    int ny = j + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                    useC[visited[nx][ny]] = false;
                }
 
            }
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cout << res[i][j];
        }
        cout << '\n';
    }
 
    return 0;
}
cs

 

반응형

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

[백준 14890번] 경사로  (0) 2022.03.16
[백준 3055번] 탈출  (0) 2022.03.13
[백준 16234번] 인구 이동  (0) 2022.03.04
[백준 13460번] 구슬 탈출 2  (0) 2022.02.10
[백준 16973번] 직사각형 탈출  (0) 2022.01.31
반응형

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

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모

www.acmicpc.net

<문제 풀이> BFS

 

BFS를 이용해서 두 인구 차이가 L 이상 R 이하를 만족하는 연결 요소를 구하면 되는데, 이때 지나온 좌표, 현재까지 인구의 합을 저장해 두고 queue가 비면 인구 이동을 진행하면 된다. 

 

현재까지의 좌표의 개수가 2개 이상일 때 두 그룹 이상이 생기는 거니깐 이 경우에만 인구 이동을 진행한다.

-> bfs가 bool을 return 하도록 하고 인구 이동이 한 번 이상 진행한 경우  true

-> bfs가 true면 다시 bfs를 호출  

 

<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
#include<iostream>
#include<utility>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
 
#define X first
#define Y second
 
const int dx[4= { 001-1 };
const int dy[4= { 1-100 };
 
int N, L, R;
int A[50][50];
bool visited[50][50];
bool bfs() {
    bool ret = false;
    fill(&visited[0][0], &visited[49][50], 0);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (visited[i][j]) continue;
            queue<pair<intint > > Q;
            vector<pair<intint> > trace;
            int tot = A[i][j];
            Q.push({ i, j });
            trace.push_back({ i, j }); //지나온 좌표 저장
            visited[i][j] = true;
            while (!Q.empty()) {
                auto cur = Q.front(); Q.pop();
                for (int dir = 0; dir < 4; dir++) {
                    int nx = cur.X + dx[dir];
                    int ny = cur.Y + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= N)continue;
                    if (visited[nx][ny])continue;
                    if (A[nx][ny] == -1)continue;
                    int diff = abs(A[nx][ny] - A[cur.X][cur.Y]);
                    if (diff< L || diff > R) continue;
                    tot += A[nx][ny]; // 인구이동이 가능하면
                    Q.push({ nx, ny });
                    visited[nx][ny] = true;
                    trace.push_back({ nx, ny });
 
                }
            }
            int trace_size = trace.size();
            if (trace_size >= 2) {
                ret = true;
                for (auto& e : trace) {
                    A[e.X][e.Y] = tot / trace_size;
                }
            }
        }
    }
 
    return ret;
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> N >> L >> R;
    fill(&A[0][0], &A[49][50], -1);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin>>A[i][j];
        }
    }
    int ans = 0;
    while (bfs()) {
        ans++;
    }
    cout << ans;
    return 0;
}
cs

 

반응형
반응형

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

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

<문제 풀이> 시뮬레이션

상하좌우 기울이기 모든 조합을 다 해보면 되는데 한번 기울였을 때 RED, BLUE가 탈출에 성공했는지 여부를 저장할 bool 변수 2개가 필요하다.

 

1. 레드만 탈출 

-> 최솟값을 갱신

2. 블루가 탈출

-> 그 상태에서 4방향으로 기울이지 않고 종료한다.

 

[Left로 기울이기]

기울인 상태를 저장할 moved[10]을 준비

idx = 0 위치에 구슬을 저장할 수 있다.

각 행에 대해서 j =0  to j = M -1 모든 열을 확인한다.

만약 board[row][j]가 벽이면 idx = j + 1 위치에 구슬을 저장할 수 있다.

만약 board[row][j]가 구멍이면 idx = j 위치에 구슬을 넣어볼 수 있고, 현재 j의 위치에 구멍이 등장했다는 표시를 한다.

만약 board[row][j]가 구슬이고 idx에 구멍이 있으면 구슬을 넣는다

만약 board[row][j]가 구슬이고 idx에 구멍이 없으면 moved[idx++]에 구슬을 넣는다.

 

배열을 90도 회전하는 걸 구현하면

left 기울이기 하나만 구현해도 right, up, down을 구현할 수 있다

 

 

<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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include<iostream>
#include<algorithm>
using namespace std;
 
int N, M;
char board[10][10];
const int INF = (1 << 30);
int res = INF;
bool left(bool &red, bool& blue) {
    for (int i = 1; i < N - 1; i++) {
        char moved[10];
        int idx = 0;
        int escapeIdx = -1;
        fill(moved, moved + 10'.');
        for (int j = 0; j < M; j++) {
            if (board[i][j] == '#') {
                moved[j] = '#';
                idx = j + 1;
            }
            else if (board[i][j] == 'O') {                
                moved[j] = 'O';
                escapeIdx = j;
                idx = j;
            }
            else if (board[i][j] == 'R' || board[i][j] == 'B') {
                if (idx != escapeIdx) {
                    moved[idx++= board[i][j];
                }
                else {
                    if (board[i][j] == 'R') red = true;
                    else if (board[i][j] == 'B') blue = true;
                }
                
            }
        }
        for (int j = 0; j < M; j++) {
            board[i][j] = moved[j];
        }
    }
    if (blue || red) return true;
    else return false;
}
void rotate() {
    char temp[10][10];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            temp[i][j] = board[i][j];
        }
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            board[j][N - 1 -i] = temp[i][j];
        }
    }
 
    swap(N, M);
 
}
 
bool down(bool &red, bool &blue) {
    rotate();
    bool ret =left(red, blue);
    rotate();
    rotate();
    rotate();
    return ret;
}
 
bool right(bool& red, bool& blue) {
    rotate();
    rotate();
    bool ret = left(red, blue);
    rotate();
    rotate();
    return ret;
}
bool up(bool& red, bool& blue) {
    rotate();
    rotate();
    rotate();
    bool ret = left(red, blue);
    rotate();
    return ret;
}
 
void backup(char temp[10][10]) {
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            board[i][j] = temp[i][j];
        }
    }
}
 
void solve(int idx) {
    if (idx == 11return;
    char temp[10][10];
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            temp[i][j] = board[i][j];
        }
    }
    bool red = false;
    bool blue = false;
    if (!left(red, blue)) {
        solve(idx + 1);
    }
    if (red && !blue) {
        res = min(res, idx);
        return;
    }
    red = false;
    blue = false;
    backup(temp);
 
    if (!up(red, blue)) {
        solve(idx + 1);
    }
    if (red && !blue) {
        res = min(res, idx);
        return;
    }
    red = false;
    blue = false;
    backup(temp);
 
    if (!right(red, blue)) {
        solve(idx + 1);
    }
    if (red && !blue) {
        res = min(res, idx);
        return;
    }
    red = false;
    blue = false;
    backup(temp);
 
    if (!down(red, blue)) {
        solve(idx + 1);
    }
    if (red && !blue) {
        res = min(res, idx);
        return;
    }
    red = false;
    blue = false;
    backup(temp);
}
 
int main(void){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
 
    solve(1);
    if (res == INF) {
        cout << -1 << '\n';
    }
    else {
        cout << res << '\n';
    }
    return 0;
}
cs

 

반응형
반응형

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

 

16973번: 직사각형 탈출

크기가 N×M인 격자판에 크기가 H×W인 직사각형이 놓여 있다. 격자판은 크기가 1×1인 칸으로 나누어져 있다. 격자판의 가장 왼쪽 위 칸은 (1, 1), 가장 오른쪽 아래 칸은 (N, M)이다. 직사각형의 가장

www.acmicpc.net

<문제 풀이> BFS

직사각형의 좌측 상단의 좌표로 BFS를 진행하면 되는데 이때 격자판을 넘어가는지, 벽을 만나는지를 체크할 때 직사각형의 전체를 확인할 필요가 없다 -> O(HW)

 다음 방향으로 이동할 때 이동한 면적만 확인하면 된다. ->O(H) or O(W)

<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
#include<iostream>
#include<queue>
#include<utility>
using namespace std;
 
#define X first
#define Y second
 
enum{LEFT, RIGHT, UP, DOWN};
int N, M;
int board[1001][1001];
int dist[1001][1001];
int H, W, Sr, Sc, Fr, Fc;
const int dx[4= { 00-11 }; //LEFT, RIGHT, UP, DOWN
const int dy[4= { -1100 };
 
bool moveable(int r, int c, int dir) {
    if (dir == LEFT) {
        if (c - 1 < 1return false;
        if (dist[r][c - 1!= -1return false;
        for (int i = 0; i < H; i++) {
            if (board[r + i][c - 1== 1return false;
        }
    }
    else if (dir == RIGHT) {
        if (c + W > M) return false;
        if (dist[r][c + 1!= -1return false;
        for (int i = 0; i < H; i++) {
            if (board[r + i][c + W] == 1return false;
        }
    }
    else if (dir == UP) {
        if (r - 1 < 1return false;
        if (dist[r - 1][c] != -1return false;
        for (int i = 0; i < W; i++) {
            if (board[r - 1][c + i] == 1return false;
        }
    }
    else if (dir == DOWN) {
        if (r + H > N) return false;
        if (dist[r + 1][c] != -1return false;
        for (int i = 0; i < W; i++) {
            if (board[r + H][c + i] == 1return false;
        }
    }
    return true;
}
int bfs() {
    queue<pair<intint> > Q;
    Q.push({ Sr, Sc });
    dist[Sr][Sc] = 0;
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        if (cur.X == Fr && cur.Y == Fc) return dist[cur.X][cur.Y];
        for (int dir = 0; dir < 4; dir++) {
            if (moveable(cur.X, cur.Y, dir)) {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];
                Q.push({nx, ny });
                dist[nx][ny] = dist[cur.X][cur.Y] + 1;
            }
        }
    }
    return -1;
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> board[i][j];
            dist[i][j] = -1;
        }
    }
    cin >>H>>>>Sr >> Sc >> Fr >> Fc;
    cout << bfs();
    return 0;
}
cs

 

 

반응형

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

[백준 16234번] 인구 이동  (0) 2022.03.04
[백준 13460번] 구슬 탈출 2  (0) 2022.02.10
[백준 16932번] 모양 만들기  (0) 2022.01.31
[백준 3190번] 뱀  (0) 2022.01.19
[백준 2638번] 치즈  (0) 2022.01.17
반응형

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

 

16932번: 모양 만들기

N×M인 배열에서 모양을 찾으려고 한다. 배열의 각 칸에는 0과 1 중의 하나가 들어있다. 두 칸이 서로 변을 공유할때, 두 칸을 인접하다고 한다. 1이 들어 있는 인접한 칸끼리 연결했을 때, 각각의

www.acmicpc.net

<문제 풀이> BFS

1. 1로 이루어진 연결 요소를 구해서 그룹화한다.

-> 그룹화는 각각의 연결 요소에 번호를 부여

 

2. 배열에서 0을 찾아서 (상하좌우 영역의 크기 + 1 ( 0을 1로 바꾼 경우))의 최댓값을 구한다.

-> 이때 같은 상하좌우를 확인할 때 같은 영역은 중복 체크하지 않도록 check 배열을 하나 둬야 한다.

<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
#include<iostream>
#include<queue>
#include<algorithm>
#include<utility>
using namespace std;
 
#define X first
#define Y second
 
int N, M;
 
const int dx[4= { 001-1 };
const int dy[4= { 1-100 };
 
 
int board[1000][1000];
bool visited[1000][1000];
bool check[1000000];
int area[1000000];
int res = 0;
int num = 1;
 
int dfs(int cx, int cy) {
    int ret = 1;
    for (int dir = 0; dir < 4; dir++) {
        int nx = cx + dx[dir];
        int ny = cy + dy[dir];
        if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
        if (board[nx][ny] != 0 && !visited[nx][ny]) {
            board[nx][ny] = num;
            visited[nx][ny] = true;
            ret += dfs(nx, ny);
        }
    }
    return ret;
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (board[i][j] == 1 && !visited[i][j]) {
                visited[i][j] = true;
                board[i][j] = num;
                area[num] = dfs(i, j);
                num++;
            }
        }
    }
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (board[i][j] == 0) {
                int temp = 1;
                for (int dir = 0; dir < 4; dir++) {
                    int nx = i + dx[dir];
                    int ny = j + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                    if (board[nx][ny] != 0 && !check[board[nx][ny]]){
                        temp += area[board[nx][ny]];
                        check[board[nx][ny]] = true;
                    }
                    
                }
                for (int dir = 0; dir < 4; dir++) {
                    int nx = i + dx[dir];
                    int ny = j + dy[dir];
                    if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                    if (board[nx][ny] != 0) {
                        check[board[nx][ny]] = false;
                    }
 
                };
                res = max(res, temp);
            }
        }
    }
    cout << res;
    return 0;
}
cs
반응형

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

[백준 13460번] 구슬 탈출 2  (0) 2022.02.10
[백준 16973번] 직사각형 탈출  (0) 2022.01.31
[백준 3190번] 뱀  (0) 2022.01.19
[백준 2638번] 치즈  (0) 2022.01.17
[백준 16985번] Maaaaaaaaaze  (0) 2022.01.16
반응형

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

 

3190번: 뱀

 'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

<문제 풀이> deque(덱), 시뮬레이션

1. deque를 이용해서 뱀을 나타낸다

-> 뱀을 한 덩어리로 생각하지 말고 길이가 n이면 크기가 1인 뱀이 n개가 이어져있다고 생각하면

-> 각각의 뱀은 현재 자신의 위치와 방향을 가지고 있습니다.

 

 

2. deque로 뱀을 표현하면 이제 문제 그대로 구현하면 됩니다.

● 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.

-> 현재 deque의 맨 마지막 뱀과 같은 방향을 가지면서 그 방향으로 1칸 이동한 좌표를 가진 뱀을 deque의 마지막에 push 한다.

● 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.

-> 사과가 있는 좌표에 뱀이 있다는 표시를 해줍니다.

● 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.

-> 맨 뒤에 꼬리만 자르면 되니깐 deque의 첫 번째 원소를 삭제합니다.

-> 이때 삭제한 뱀의 좌표에 뱀이 없다는 표시를 남겨줍니다.

 

종료 조건은 새로운 뱀이 벽을 만나거나 뱀을 만나면 종료하면 됩니다.

 

3. 근데 만약 현재 X초이고 X초가 끝난 뒤에 방향 변환 정보가 있다면

-> 새로운 뱀을 추가하기 전에 제일 뒤에 있는 뱀(머리)에 방향을 바꿔주면 됩니다.

 

방향 전환 및 표현은 소스 코드를 보시면 쉽게 이해하실 수 있습니다.

 

 

<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
#include <iostream>
#include <deque>
using namespace std;
 
#define EMPTY 0
#define APPLE 1
#define SNAKE 2
enum {
    LEFT,
    RIGHT,
    UP,
    DOWN
}; 
 
const int dx[4= {00-11}; // LEFT, RIGHT, UP, DOWN
const int dy[4= {-1100};
 
class body {
public:
    int x;
    int y;
    int dir;
    body(int x, int y, int dir) {
        this->= x;
        this->= y;
        this->dir = dir;
    }
};
 
int board[101][101];
char rotateInfo[10001];
int N;
void rotateLeft(body &b) {
    if (b.dir == LEFT) {
        b.dir = DOWN;
    }
    else if (b.dir == RIGHT) {
        b.dir = UP;
    }
    else if (b.dir == UP) {
        b.dir = LEFT;
    }
    else if (b.dir == DOWN) {
        b.dir = RIGHT;
    }
}
void rotateRight(body &b) {
    if (b.dir == LEFT) {
        b.dir = UP;
    }
    else if (b.dir == RIGHT) {
        b.dir = DOWN;
    }
    else if (b.dir == UP) {
        b.dir = RIGHT;
    }
    else if (b.dir == DOWN) {
        b.dir = LEFT;
    }
}
 
int move() {
    int second = 0// 현재 흐른 시간
    board[1][1= SNAKE; //맨위 맨좌측에서 시작
    body b(11, RIGHT); //뱀은 처음에 오른쪽을 향한다.
    deque<body> dq;
    dq.push_back(b);
    while (true) {
        auto head = dq.back();
        if (rotateInfo[second]) { //second 초가 끝난 뒤에 방향 변환 정보가 존재하면
            dq.pop_back(); 
            if (rotateInfo[second] == 'L') {
                rotateLeft(head);
                dq.push_back(head);
            }
            else if (rotateInfo[second] == 'D') {
                rotateRight(head);
                dq.push_back(head);
            }
        }
        second++;
        int nx = head.x + dx[head.dir];
        int ny = head.y + dy[head.dir];
        body new_head(nx, ny, head.dir);
        dq.push_back(new_head); // 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
        if (nx <1 || ny <1 || nx > N || ny > N || board[nx][ny] == SNAKE) { //벽 또는 자기자신의 몸과 부딪히면
            return second; //종료
        }
        if (board[nx][ny] == APPLE) {   //만약 이동한 위치에 사과가 있다면
            board[nx][ny] = SNAKE; //그 칸에 있던 사과가 없어진다.
        }
        else if (board[nx][ny] == EMPTY) { //만약 이동한 위치에 사과가 없다면
            board[nx][ny] = SNAKE;
            board[dq.front().x][dq.front().y] = EMPTY;
            dq.pop_front(); // 몸길이를 줄인다.
        }
    }
 
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> N;
    int k; cin >> k;
    while (k--) {
        int r, c; cin >> r >> c;
        board[r][c] = APPLE;
    }
    int L; cin >> L;
    while (L--) {
        int X; 
        char C; 
        cin >> X >> C;
        rotateInfo[X] = C;
    }
    cout << move();
 
    return 0;
}
cs

 

반응형

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

[백준 16973번] 직사각형 탈출  (0) 2022.01.31
[백준 16932번] 모양 만들기  (0) 2022.01.31
[백준 2638번] 치즈  (0) 2022.01.17
[백준 16985번] Maaaaaaaaaze  (0) 2022.01.16
[백준 14499번] 주사위 굴리기  (0) 2022.01.15
반응형

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

 

2638번: 치즈

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5 ≤ N, M ≤ 100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로

www.acmicpc.net

<문제 풀이> BFS

1. BFS로 (0,0)에서 공기를 출발시킨다.

2. 공기가 치즈를 2번 터치하는지 체크하고 만약 2번 터치를 했다면 임시 큐에 치즈가 녹을 자리를 넣어준다

3. 공기 BFS에 큐가 모두 비게 되면 임시 큐에 저장했던 치즈가 녹은 자리를 다시 공기 큐에 넣어준다

-> 치즈가 녹은 자리는 다시 공기가 채워지므로 공기의 다음 시작 위치가 됨

 

<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
#include <iostream>
#include <utility>
#include <queue>
using namespace std;
 
#define X first
#define Y second
 
int N, M;
int board[100][100];
bool visited[100][100];
int hour[100][100];
const int dx[4= { 001-1 };
const int dy[4= { 1-100 };
 
void bfs() {
    int res = 0;
    queue<pair<intint> >Q;
    Q.push({ 00 });
    visited[0][0= true;
    while (true) {
        queue<pair<intint> > temp; //치즈가 녹은 자리에서 공기 BFS 시작
        while (!Q.empty()) {
            auto cur = Q.front(); Q.pop();
            for (int dir = 0; dir < 4; dir++) {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];
                if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                if (board[nx][ny] == 1) {
                    if (visited[nx][ny]) { //공기가 치즈를 2번 터치하면
                        temp.push({ nx,ny });
                        board[nx][ny] = 0;
                        hour[nx][ny] = hour[cur.X][cur.Y] + 1;
 
                    }
                    else {
                        visited[nx][ny] = true;
                    }
                }
                else {
                    if (!visited[nx][ny]) {
                        Q.push({ nx, ny });
                        visited[nx][ny] = true;
                    }
                }
 
            }
        }
        if (temp.size() == 0) { //더이상 남아있는 치즈가 없는 경우
            cout << res;
            return;
        }
        res++;
        while (!temp.empty()) {
            Q.push(temp.front()); temp.pop();
 
        }
    }
}
 
int main(void) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
 
    cin >> N >> M;
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
    bfs();
    
 
    return 0;
}
cs

 

반응형

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

[백준 16932번] 모양 만들기  (0) 2022.01.31
[백준 3190번] 뱀  (0) 2022.01.19
[백준 16985번] Maaaaaaaaaze  (0) 2022.01.16
[백준 14499번] 주사위 굴리기  (0) 2022.01.15
[백준 6443번] 애너그램  (0) 2022.01.14

+ Recent posts