1주차 스터디(23.11.09) - 완전 탐색 (Brute Force)

2023. 11. 7. 16:18스터디

코딩테스트 대비 스터디를 시작하면서, 첫 주차 알고리즘은 완전 탐색(Brute Force).

 

대표문제로서 선택된 것이 프로그래머스 - 카펫 (Level 2)

 

1. 카펫

 

 

해당 문제 풀이 코드는 이하와 같습니다.

#풀이 1 (Yellow 활용)
import math
def solution1(brown, yellow):
    a = brown + yellow #전체 타일 갯수 a
    for i in range (1,int(math.sqrt(a))+1): #a = i * (a//i) = i * b (i <= b)
        if a % i == 0:
            b = a // i 
            if (i - 2) * (b - 2) == yellow: #yellow = (i-2) * (b-2)
                answer = [b,i]
                return answer

#풀이 2 (전체 활용)
def solution2(brown,yellow):
    for i in range (1,int(math.sqrt(yellow))+1): #yellow = i * (yellow//i) = i * b (i <= b)
        if yellow % i == 0:
            b = yellow // i 
            if (i + 2) * (b + 2) == brown + yellow: #brown + yellow = (i+2) * (b+2)
                answer = [b+2,i+2]
                return answer
brown,yellow = map(int,input().split())
print(solution1(brown,yellow))
print(solution2(brown,yellow))

 

첫 번째는, Yellow 타일과 Brown 타일의 개수를 합친다면 전체 타일 개수가 나온다는 점을 활용하는 풀이

 

주목할 점은 Yellow 타일의 개수 = (타일의 가로길이 - 2) * (타일의 세로길이 - 2)라는 점입니다.

 

그래서, 전체 타일 갯수 a  = i * (a // i) (가로 x 세로)로 나눈 뒤, 

 

yellow = (i - 2) * (a // i - 2)가 되는지 확인하는 방법입니다.

 

두 번째는, 첫 번째의 반대 순서로 생각해내가는 방법입니다.

 

브루트포스 방법으로 한다면, 아마 다음과 같이 되지 않을까 싶습니다.

 

이후, 따로 준비한 문제 두 개는 백준 1051번 숫자 정사각형  (실버 3), 백준 2468 안전 영역 (실버 1)이다.

 

숫자 정사각형은 정직하게 풀면 쉽게 풀리고, 안전 영역은 DFS, BFS와 연관 지을 수 있기 때문에 추가적으로 학습했다.

 

2. 숫자 정사각형

 

#BOJ 1051 숫자정사각형 실버3
N,M = map(int,input().split())
A = []
for i in range (0,N):
    a = list(str(input()))
    A.append(a)
ans = []
for i in range (1,N+1):
    for x in range (0,N-i+1):
        for y in range (0,M-i+1):
            B = list(set([A[x][y],A[x][y+i-1],A[x+i-1][y],A[x+i-1][y+i-1]]))
            if len(B) == 1:
                ans.append(i*i)
            else:
                continue
print(max(ans))

 

아이디어는 n  * n 정사각형을 생각 한 뒤, 각 정사각형의 꼭짓점이 (시작점 A[i][j]을 포함하여) A[i][j+n-1],A[i+n-1][j] , A[i+n-1][j+n-1] 으로 나타내어진다는 것에 주목하면 좋다.

 

만약, 위 네점에 해당하는 값이 전부 같다면, set 함수를 사용하여 중복되는 값들을 전부 삭제할 수 있기 때문에 set( - )의 길이는 1이 되겠다.

 

하지만 한 점이라도 해당하는 값이 다르다면, set에 의해 만들어지는 튜플의 길이가 2 이상이 되기 때문에 간단하게 판단할 수 있다.

 

ex) 1,1,1,2 -> 1,2  / 2,2,2,2 -> 2 / 3,2,3,4 -> 2,3,4 .....

 

이후, 만약 set에 의해 생성되는 튜플의 길이가 1이라면 정사각형의 넓이는 n * n 으로 주어지므로 이를 ans에 추가.

(혹은 max 함수를 사용하는 것도 좋아보인다.)

 

그 뒤 ans의 최댓값을 반환하면 끝.

 

 

3. 안전 지대

 

 

from collections import deque
N = int(input())
A = []
max_height = 0
for i in range (0,N):
    a = list(map(int,input().split()))
    max_height = max(max(a),max_height)
    A.append(a)

def move(x,y,h):
    dxdy = [[1,0],[-1,0],[0,1],[0,-1]]
    z = []
    for i in range (0,4):
        a = x + dxdy[i][0]
        b = y + dxdy[i][1]
        if 0 <= a < N and 0 <= b < N and A[a][b] > h:
            z.append([a,b])
    return z
ans = []

for height in range (0,max_height):
    cnt = 0
    visited = [[False for _ in range (0,N)] for _ in range (0,N)]
    for i in range (0,N):
        for j in range (0,N): 
            if A[i][j] > height and visited[i][j] == False:
                visited[i][j] = True
                a = deque([])
                a.appendleft([i,j])
                while a:
                    c = a.popleft()
                    visited[c[0]][c[1]] = True
                    b = move(c[0],c[1],height)
                    for area in b:
                        if visited[area[0]][area[1]] == False:
                            visited[area[0]][area[1]] = True
                            a.appendleft([area[0],area[1]])
                cnt += 1
    ans.append(cnt)      
print(max(ans))

 

 

아이디어는 다음과 같다.

 

1. 최고 높이 max_height 구하기 (for문을 통해 0~max_height까지 전부 체크하기 위함)

 

2. DFS, BFS를 통하여 연결 요소의 갯수를 구하기

(이 과정에서 높이가 1에서 구한 변수보다 높은지 판정이 필요함)

 

3. 연결요소의 갯수를 저장하는 리스트를 만든 뒤, 그 뒤 최댓값 반환

 

느낀 점

 

브루트포스 알고리즘에서 백트래킹 (끝까지 탐색을 완료하면 뒤로 돌아가는)에 관련된 문제가 많았다는 것을 알 수 있었다.

 

또한 DFS,BFS와 연계되어있는 문제가 많아 보이므로 그 부분에 대해 추가 공부를 하는 것도 좋아 보인다. 

'스터디' 카테고리의 다른 글

[혼자 공부한] 분리집합  (0) 2024.08.15
4주차 스터디(23.12.01)-2  (1) 2023.12.01
4주차 스터디(23.12.01)  (1) 2023.11.30
3주차 스터디(23.11.24)  (0) 2023.11.30
2주차 스터디(23.11.16) - DFS, BFS  (0) 2023.11.11