새소식

PS/백준

[백준/18809] Gaaaaaaaaaarden (Python)

  • -

Problem : 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

 

Difficulty : Gold 1

 

Status : Solved (pypy3)

 

Time : 00:33:07

 


 

문제 설명

 

더보기

 

길고 길었던 겨울이 끝나고 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개 이하이다.

 

출력

 

첫째 줄에 피울 수 있는 꽃의 최대 개수를 출력한다.

 

입력 예시

 

2 2 1 1
2 1
1 2

 

출력 예시

 

2

 

 


 

풀이

 

그래프 탐색 시뮬레이션 문제. 초기 배양액을 뿌릴 수 있는 경우의 수는 최대 (10개의 장소중 G개의 초록 배양액을 뿌리는 조합) x (10 - R 개의 장소 중 G개의 초록 배양액을 뿌리는 조합)이 된다. 각각의 조합에 대해 그래프 탐색을 진행하도록 하자.

 

  • 현재 주기에서 방문할 수 있는 좌표들과, 좌표 타입(r, g)을 가지고 시작한다.
  • 각 좌표의 상하좌우 중 방문 가능한 좌표를 저장한다. 이 때, 방문 가능한 좌표의 타입 역시 저장한다.
  • 앞서 저장한 방문 가능한 좌표들은 이 주기에서 방문된 모든 좌표들을 포함한다. 이 좌표들을 방문한 좌표로 바꾸어주고, 다음 두 가지 경우를 처리한다.
    • 좌표 타입이 한 가지일 경우 : 다음 주기에 방문할 좌표로 저장한다.
    • 좌표 타입이 여러 가지일 경우 : 이 경우 두 배양액이 동시에 만났다는 의미이므로, 꽃이 피어났다고 볼 수 있다. 따라서 다음 주기에 방문할 좌표로 저장할 필요가 없다. 또한 꽃이 피어났으므로 1을 카운트한다.
  • 더 이상 방문할 수 없을 때까지 위 과정을 반복하면, 이 조합에서 피어날 수 있는 총 꽃송이 수가 모두 카운트된다. 모든 조합에 대해 위 알고리즘을 시행하도록 하자.

 

...파이썬으로는 시간초과가 나는 건 둘째치고, 다른 풀이에 비해 훨씬 더 많은 시간이 소요된다. 아마 주기마다 함수가 호출되는 문제가 원인으로 추정된다. 한 개의 큐를 사용해 풀이했어야 하나 싶다.

 

풀이 코드

from itertools import combinations
from collections import defaultdict
import sys

input = sys.stdin.readline
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]

N, M, G, R = map(int, input().split())
map_list = [list(map(int, input().split())) for _ in range(N)]
start_list = list()
for i in range(N) :
  for j in range(M) :
    if map_list[i][j] == 2 :
      start_list.append((j, i))

def bfs_ones(q, visited) :
  next_dict = defaultdict(set)
  next_q = list()
  cnt = 0
  for x, y, typ in q :
    for k in range(4) :
      ax, ay = x + dx[k], y + dy[k]
      if -1 < ax < M and -1 < ay < N and map_list[ay][ax] and not visited[ay][ax] :
        next_dict[(ax, ay)].add(typ)
  for (x, y), val in next_dict.items() :
    visited[y][x] = True
    if len(val) > 1 :
      cnt += 1
      continue
    next_q.append((x, y, list(val)[0]))
  return next_q, cnt

def search(q, visited) :
  result = 0
  while q :
    q, cnt = bfs_ones(q, visited)
    result += cnt
  return result

answer = 0
for r_val in combinations(range(len(start_list)), R) :
  left_list = [ x for x in range(len(start_list)) if x not in r_val]
  for g_val in combinations(left_list, G) :
    q = list()
    visited = [[False]*M for _ in range(N)]
    for r in r_val :
      x, y = start_list[r]
      visited[y][x] = True
      q.append((x, y, 0))
    for g in g_val :
      x, y = start_list[g]
      visited[y][x] = True
      q.append((x, y, 1))
    result = search(q, visited)
    answer = max(answer, result)
print(answer)

풀이 완료!

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

[백준/11559] Puyo Puyo (Python)  (0) 2023.06.25
[백준/2879] 코딩은 예쁘게 (Python)  (1) 2023.06.24
[백준/2251] 물통 (Python)  (0) 2023.06.22
[백준/1461] 도서관 (Python)  (0) 2023.06.20
[백준/17609] 회문 (Python)  (0) 2023.06.20
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.