-
#18809 GaaaaaaaaaardenCode/BOJ 2020. 3. 21. 16:47728x90반응형
출처:https://www.acmicpc.net/problem/18809
18809번: Gaaaaaaaaaarden
첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두고 주어진다. 그 다음 N개의 줄에는 각 줄마다 정원의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0, 1, 2이다. 0은 호수, 1은 배양액을 뿌릴 수 없는 땅, 2는 배양
www.acmicpc.net
문제
길고 길었던 겨울이 끝나고 BOJ 마을에도 봄이 찾아왔다. BOJ 마을에서는 꽃을 마을 소유의 정원에 피우려고 한다. 정원은 땅과 호수로 이루어져 있고 2차원 격자판 모양이다.
인건비 절감을 위해 BOJ 마을에서는 직접 사람이 씨앗을 심는 대신 초록색 배양액과 빨간색 배양액을 땅에 적절하게 뿌려서 꽃을 피울 것이다. 이 때 배양액을 뿌릴 수 있는 땅은 미리 정해져있다.
배양액은 매 초마다 이전에 배양액이 도달한 적이 없는 인접한 땅으로 퍼져간다.
아래는 초록색 배양액 2개를 뿌렸을 때의 예시이다. 하얀색 칸은 배양액을 뿌릴 수 없는 땅을, 황토색 칸은 배양액을 뿌릴 수 있는 땅을, 하늘색 칸은 호수를 의미한다.
초록색 배양액과 빨간색 배양액이 동일한 시간에 도달한 땅에서는 두 배양액이 합쳐져서 꽃이 피어난다. 꽃이 피어난 땅에서는 배양액이 사라지기 때문에 더 이상 인접한 땅으로 배양액을 퍼트리지 않는다.
아래는 초록색 배양액 2개와 빨간색 배양액 2개를 뿌렸을 때의 예시이다.
배양액은 봄이 지나면 사용할 수 없게 되므로 주어진 모든 배양액을 남김없이 사용해야 한다. 예를 들어 초록색 배양액 2개와 빨간색 배양액 2개가 주어졌는데 초록색 배양액 1개를 땅에 뿌리지 않고, 초록색 배양액 1개와 빨간색 배양액 2개만을 사용하는 것은 불가능하다.
또한 모든 배양액은 서로 다른 곳에 뿌려져야 한다.
정원과 두 배양액의 개수가 주어져있을 때 피울 수 있는 꽃의 최대 개수를 구해보자.
입력
첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두고 주어진다.
그 다음 N개의 줄에는 각 줄마다 정원의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0, 1, 2이다. 0은 호수, 1은 배양액을 뿌릴 수 없는 땅, 2는 배양액을 뿌릴 수 있는 땅을 의미한다.
배양액을 뿌릴 수 있는 땅의 수는 R+G개 이상이고 10개 이하이다.
출력
첫째 줄에 피울 수 있는 꽃의 최대 개수를 출력한다.
풀이
전형적인 삼성역량테스트 느낌의 dfs+bfs문제
사실상 dfs로 배양액을 분배하는 곳과 어떤 배양액을 쓸지만 잘 구현해낸다면 bfs구현은 문제없이 해결할 수 있다.
bfs구현에서 조심해야 할 점은 꽃이 된 자리는 다음 영역으로 넓혀가서는 안된다. (이거 찾는데 30분이나 걸림)
코드
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters//배양액이 동시에 떨어지는 곳에 꽃이 피어남 //황토색 땅이 5곳 이라면 // 배양액이 2개, 2개다? //0은 호수, 1은 배양액을 뿌릴 수 없는 땅, 2는 배양액을 뿌릴 수 있는 땅 #include <iostream> #include <queue> #include <vector> #include <cstring> #include <algorithm> using namespace std; int dir[4][2] = { {1,0}, { 0,1 }, { -1,0 }, { 0,-1 } }; //n,m,G,R int n, m, G, R; int map[51][51]; int svisit[11]; int ans; typedef struct xy { int x, y; }; typedef struct info { int TIME;// 배양액이 뿌려진 시점 int color;// 뿌려진 배양액의 색 bool flower;// 꽃이 피어진 자리인가 }; info visit[51][51]; vector <xy> save;//배양액을 뿌릴 수 있는 땅에 대한 좌표 int savesz; int bfs() { memset(visit, 0, sizeof(visit)); int TIME = 1; queue<xy> greenq; queue<xy> redq; int ret = 0;// 꽃의 갯수 for (int i = 0; i < savesz; i++) { //cout << svisit[i] << " ";// if (svisit[i] == 1) {//green int x = save[i].x,y= save[i].y; greenq.push({ x,y }); visit[x][y] = {TIME,1,0}; } else if (svisit[i] == 2) { int x = save[i].x, y = save[i].y; redq.push({ x,y }); visit[x][y] = {TIME,2,0}; } } //cout << endl;// //초기 배양액 위치 //for (int i = 0; i < n; i++) { // for (int j = 0; j < m; j++) { // cout << visit[i][j].color << " "; // }cout << endl; //}cout << endl; while (!(greenq.size()==0 && redq.size()==0)) { int sz = greenq.size(); TIME++; while (sz--) {//green먼저 땅 넓히기 int fx = greenq.front().x, fy = greenq.front().y; greenq.pop(); if (visit[fx][fy].color == 5)continue; for (int d = 0; d < 4; d++) { int nx = fx + dir[d][0], ny = fy + dir[d][1]; if (nx < 0 || ny < 0 || nx >= n || ny >= m)continue; if (!map[nx][ny])continue; if (visit[nx][ny].color == 0) { visit[nx][ny] = { TIME,1,0 }; greenq.push({ nx,ny }); } } } sz = redq.size(); while (sz--) { int fx = redq.front().x, fy = redq.front().y; redq.pop(); for (int d = 0; d < 4; d++) { int nx = fx + dir[d][0], ny = fy + dir[d][1]; if (nx < 0 || ny < 0 || nx >= n || ny >= m)continue; if (!map[nx][ny])continue; if (!visit[nx][ny].flower && visit[nx][ny].color == 1 && visit[nx][ny].TIME == TIME) { ret++; visit[nx][ny].flower = true; visit[nx][ny].color = 5; continue; } if (visit[nx][ny].color)continue; visit[nx][ny].TIME = TIME; visit[nx][ny].color = 2; redq.push({ nx,ny }); } } } //동시에 ! 같은 곳을 가면 꽃이 핌 //if (ret == 6) { // cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; // for (int i = 0; i < n; i++) { // for (int j = 0; j < m; j++) { // cout << visit[i][j].color << " "; // }cout << endl; // } //} return ret; } void dfs(int num,int cnt,int gcnt,int rcnt) { //배양액 넣을건데..배양액 갯수 중에서 R+G개 만큼 뽑고 //svisit에 1,2로 어디에 어떤거 줄건지 구분 //cout << "num " << num << " cnt " << cnt << " gcnt " << gcnt << " rcnt " << rcnt << endl; if (rcnt+gcnt == G + R) { int ret=bfs(); ans = max(ans, ret); return; } for (int i = num; i < savesz; i++) { if (svisit[i])continue; if (gcnt < G) { svisit[i] = 1; dfs(i, cnt + 1, gcnt + 1, rcnt); svisit[i] = false; } if (rcnt < R) { svisit[i] = 2; dfs(i, cnt + 1, gcnt, rcnt + 1); svisit[i] = false; } } } void Input() { cin >> n >> m >> G >> R; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> map[i][j]; if (map[i][j] == 2) { save.push_back({ i,j }); } } } savesz = save.size(); } int main() { cin.tie(0); cin.sync_with_stdio(0); Input(); dfs(0, 0, 0, 0); cout << ans << endl; } 728x90반응형'Code > BOJ' 카테고리의 다른 글
#15683 감시 (0) 2020.03.23 #18808 스티커 붙이기 (0) 2020.03.21 #15949 Piet (0) 2020.03.21 #11967 불켜기 (0) 2020.03.12 #16197 두 동전 (0) 2020.03.12