반응형

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

 

18809번: Gaaaaaaaaaarden

첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두

www.acmicpc.net

<문제 풀이> 백트랙킹

1. 배양액을 뿌릴 수 있는 땅에 대해서 같은 것이 있는 순열(RRRGG...)을 구한다.

2. 뽑은 수열에 대해서 큐 두 개를 준비해서 빨간색 배양액, 초록색 배양액을 동시에 BFS를 진행한다.

-> 큐에는 항상 같은 레벨(같은 초)의 좌표가 들어간다.

-> 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
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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
#define X first
#define Y second
 
int dx[4= {0 , 01-1};
int dy[4= { 1-100 };
 
int N, M, G, R;
int G_temp, R_temp;
int board[50][50];
int backup[50][50]; //board 백업용
int visited[50][50]; //배양액 방문 체크 -> 1 == R, 2 == G
int R_visited[50][50]; //R배양액 BFS 방문 체크
int G_visited[50][50]; //G배양액 BFS 방문 체크
int res = 0// 꽃의 최대 개수
 
 
//R배양액, G배양액 퍼트리기
void BFS() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            backup[i][j] = board[i][j]; //board 배열을 다시 사용하기 위해 백업
        }
    }
    queue<pair<intint> > red, green;
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (visited[i][j] == 1) { //R 배양액이면
                red.push({ i, j });
                R_visited[i][j] = true;
            }
            else if (visited[i][j] == 2) { // G 배양액이면
                green.push({ i, j });
                G_visited[i][j] = true;
            }
        }
    }
 
    int cnt = 0//꽃의 개수
    while (!red.empty() || !green.empty()) {
 
        int red_size = red.size();
        for (int i = 0; i < red_size; i++) {
            auto cur = red.front(); red.pop();
            if (board[cur.X][cur.Y] == 3continue//만약 꽃이 피어난 곳이면 무시
            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 (R_visited[nx][ny] || board[nx][ny] == 0)continue//방문했거나 호수이면 무시
                if (board[nx][ny] == 3)continue// 꽃이 피어난 곳은 무시
                if (G_visited[nx][ny] && G_visited[nx][ny] != R_visited[cur.X][cur.Y] + 1)continue//배양액은 서로 다른 곳에 뿌려져야한다.
                else if (G_visited[nx][ny] && G_visited[nx][ny] == R_visited[cur.X][cur.Y] + 1) {//만약 동일한 시간에 두 배양액이 합쳐지면
                    board[nx][ny] = 3;  //꽃이 피어난다.
                    cnt++;
                    R_visited[nx][ny] = R_visited[cur.X][cur.Y] + 1;
                    continue;
                }
                R_visited[nx][ny] = R_visited[cur.X][cur.Y] + 1;
                red.push({ nx, ny });
            }
        }
 
        int green_size = green.size();
        for (int i = 0; i < green_size; i++) {
            auto cur = green.front(); green.pop();
            if (board[cur.X][cur.Y] == 3continue//만약 꽃이 피어난 곳이면 무시
            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 (G_visited[nx][ny] || board[nx][ny] == 0)continue//방문했거나 호수이면 무시
                if (board[nx][ny] == 3)continue// 꽃이 피어난 곳은 무시
                if (R_visited[nx][ny] && R_visited[nx][ny] != G_visited[cur.X][cur.Y] + 1)continue//배양액은 서로 다른 곳에 뿌려져야한다.
                else if (R_visited[nx][ny] && R_visited[nx][ny] == G_visited[cur.X][cur.Y] + 1) {//만약 동일한 시간에 두 배양액이 합쳐지면
                    board[nx][ny] = 3;  //꽃이 피어난다.
                    cnt++;
                    G_visited[nx][ny] = G_visited[cur.X][cur.Y] + 1;
                    continue;
                }
                G_visited[nx][ny] = G_visited[cur.X][cur.Y] + 1;
                green.push({ nx, ny });
            }
        }
    }
 
    res = max(res, cnt); //최대 꽃의 개수 
 
    /*초기화*/
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            board[i][j] = backup[i][j];
            R_visited[i][j] = 0;
            G_visited[i][j] = 0;
        }
    }
}
 
//N*N 격자에서 초록색 배양액 G개, 빨간색 배양액 R개를 뽑는 조합
void dfs(int cur, int k) {
    if (k == G + R) { //초록색 배양액 G개, 빨간색 배양액 R개를 뿌렸으면
        BFS();
        return;
    }
    for (int i = cur + 1; i < N * M; i++) {
        int x = i / M;
        int y = i % M;
        if (board[x][y] == 2) { // 배양액을 뿌릴 수 있으면
            if (R_temp != 0) { // R 배양액을 다 못뿌렸으면
                R_temp--;
                visited[x][y] = 1;
                dfs(i, k + 1);
                visited[x][y] = 0;
                R_temp++;
            }
            if (G_temp != 0) { // G 배양액을 다 못뿌렸으면 
                G_temp--;
                visited[x][y] = 2;
                dfs(i, k + 1);
                visited[x][y] = 0;
                G_temp++;
            }
        }
    }
}
 
 
 
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> N >> M >> G >> R;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
    G_temp = G;
    R_temp = R;
    dfs(-10);
    cout << res;
    return 0;
}
 
 
cs

 

반응형

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

[백준 15683번] 감시  (1) 2022.01.04
[백준 1987번] 알파벳  (0) 2022.01.03
[백준 1799번] 비숍  (0) 2021.12.31
[백준 1941번] 소문난 칠공주  (0) 2021.12.31
[백준 16987번] 계란으로 계란치기  (0) 2021.12.30

+ Recent posts