티스토리 뷰

알고리즘/백준

백준 18809 Gaaaaaaaaaarden C++

4567은 소수 2022. 12. 21. 18:39

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

노란색 칸은 배양액을 뿌릴 수 있는 위치, 흰색은 배양액을 뿌릴 수는 없지만 퍼질 수 있는 위치, 파란색은 호수로 이루어져 있습니다.

이 때 빨간색 배양액과 초록색 배양액을 모두 뿌렸을 때 (겹치게 뿌리면 안 됨) 동시에 만나는 지점에서 꽃이 피고, 이 때 꽃의 최대 개수를 구하는 문제입니다.

 

전체 칸이 50x50, 배양액 개수가 최대 5,5 개, 노란색 칸이 최대 10개이므로 브루트포스로도 충분합니다.

(백트래킹 등을 이용하면 더 줄일 수는 있겠지만 브루트포스로도 시간 초과는 안 납니다.)

배양액을 뿌리는 위치가 최대 10!/5!5! = 252 이고 최대 2500칸을 bfs로 탐색한다고 하면 각 케이스마다 대략 10만번 탐색을 진행하게 됩니다.

 

그러므로 빨간색 배양액과 초록색 배양액 위치를 큐에 넣고 퍼져나갈 때마다 그 칸에 도달한 시간을 같이 체크해주면 됩니다. 그리고 그것을 모든 케이스에 대해 반복해줍니다. 

(단 노란색 칸 위치 번호가 012345 이고 초록색이 3개, 빨간색이 3개일 때 012 / 345 와 021 / 543 은 같은 케이스이므로 이런 경우는 map을 이용해 체크하였습니다.)

 

코드는 다음과 같습니다.

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <map>
#include <queue>

using namespace std;

// 칸 : n x m
// 배양액 : g, r
// 황토색 칸에만 뿌릴 수 있음 (2)
// 흰 칸에는 못 뿌림 (1)
// 1초 당 인접칸으로 퍼져나감
// 호수에는 안 퍼짐 (0)
// 원래 배양액 있는 곳으로도 안 퍼짐
// g, r 동시에 만나는 지점에 꽃 핌
// g, r개 배양액은 모두 써야 함
// 최대 꽃 개수는?

// 칸 최대 2500개
// 배양액 최대 10개
// g, r 최대 5개
// 배양액 위치 : 10!/5!5! = 252
// 각 케이스마다 브루트포스해도 얼추 10만번 정도

int n, m, g, r;
int land[51][51];
pair<int,int> yellow[11]; // 황색 땅 번호, 위치
map<string, bool> checkMap;
// 황색 땅 위치에 뿌렸었는지 체크용 (string은 sort한 상태로 넣기)
// 최대 10개이므로 0123456789 와 같이 넣기
int flower; // 꽃 개수

int dy[4] = {0,0,1,-1};
int dx[4] = {1,-1,0,0};
int cnt = 0; // yellow 칸 개수 

void init()
{
  cin >> n >> m >> g >> r;
  
  for(int i = 0; i < n; i++) {
    for(int j = 0; j < m; j++) {
      cin >> land[i][j];
      if(land[i][j] == 2) {
        yellow[cnt] = {i, j};
        cnt++;
      }
    }
  }
  flower = -1;
}

int bfs(string green, string red)
{
  int res = 0; // 꽃 개수 
  // green : 0123, red : 5678
  // 0,1,2,3번 yellow 땅에 g
  // 5,6,7,8번 yellow 땅에 r 넣는 경우

  pair<int,char> check[51][51];
  // {시간, 색}
  // 색 : g, r, f
  for(int i = 0; i < n; i++) {
    for(int j = 0; j < m; j++) {
      check[i][j] = {-1, 'b'}; // blank
    }
  }
  
  queue<pair<int,int>> q;

  for(int i = 0; i < green.size(); i++) {
    pair<int,int> gg = yellow[green[i] - '0'];
    q.push(gg);
    check[gg.first][gg.second] = {0, 'g'};
  }
  for(int i = 0; i < red.size(); i++) {
    pair<int,int> rr = yellow[red[i] - '0'];
    q.push(rr);
    check[rr.first][rr.second] = {0, 'r'};
  }

  while(!q.empty()) {
    pair<int,int> loc = q.front();
    q.pop();

    int t = check[loc.first][loc.second].first;
    char c = check[loc.first][loc.second].second;
    
    // 꽃인 경우
    if(c == 'f')
      continue;

    for(int i = 0; i < 4; i++) {
      int ny = loc.first + dy[i];
      int nx = loc.second + dx[i];

      // 벗어남
      if(ny < 0 || nx < 0 || ny >= n || nx >= m)
        continue;
      // 호수인 경우
      if(land[ny][nx] == 0)
        continue;

      int nt = t + 1;
      char nc = check[ny][nx].second;
      // 빈 칸인 경우
      if(nc == 'b') {
        check[ny][nx] = {nt, c};
        q.push({ny, nx});
      }
      else {
        // 배양액 만나는 경우
        if(nt == check[ny][nx].first && nc != c) {
          check[ny][nx] = {-1, 'f'};
          res++;
        }
        // 배양액 있는 경우
        else {
          continue;
        }
      }
    }
  }

  return res;
}

void calc()
{
  string gstr = "";
  string rstr = "";
  string str = "";
  for(int i = 0; i < cnt; i++) {
    str += char(i + '0');
  }

  do {
    gstr = str.substr(0, g);
    rstr = str.substr(g, r);

    sort(gstr.begin(), gstr.end());
    sort(rstr.begin(), rstr.end());
    
    string tmp = gstr + rstr;
    // 처음 탐색하는 값
    if(checkMap.find(tmp) == checkMap.end()) {
      checkMap.insert({tmp, true});
      flower = max(flower, bfs(gstr, rstr));
    }
    
  } while(next_permutation(str.begin(), str.end()));

  cout << flower;
}

int main() {
  ios_base :: sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  init();
  calc();
}

'알고리즘 > 백준' 카테고리의 다른 글

백준 2836 수상 택시 C++  (0) 2023.01.28
백준 1799 비숍 C++  (0) 2023.01.05
백준 1695 팰린드롬 만들기 C++  (0) 2022.12.11
백준 3108 로고 C++  (0) 2022.12.05
백준 15718 돌아온 떡파이어 C++  (0) 2022.11.10
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2025/02   »
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
글 보관함