[알고리즘 프로그래머스] 카펫 (LEVEL 2)

(문제) 카펫 (LEVEL 2) [완전탐색]


Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다.



Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.

Leo가 본 카펫에서 갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 solution 함수를 작성해주세요.

입력설명

첫번째 입력으로는 갈색 개수가 들어오고, 두번째 입력으로는 노랑색 개수가 들어옵니다.

갈색 격자의 수 brown은 8 이상 5,000 이하인 자연수입니다.

노란색 격자의 수 yellow는 1 이상 2,000,000 이하인 자연수입니다.

카펫의 가로 길이는 세로 길이와 같거나, 세로 길이보다 깁니다.

출력설명

갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return

테스트케이스

입력예제 출력예제
10 2 [4, 3]
8 1 [3, 3]
24 24 [8, 6]

해결방법

방법1 Brown 사용하여 넓이로 접근

수학적 방법으로 도달해야 하는 문제다.

우리가 먼저 알아야하는 것은 갈색은 네모의 테두리 이다.

네모의 테두리의 개수를 구해보자.

갈색의 개수를 구하는 공식은 다음과 같다.

(가로 + 세로 - 2) * 2 이다.

필자는 처음에 “왜??” 라는 의문을 품었다. 하지만 필자는 엄청 멍청해서 이해를 못했던 것이다.

자 그림을 통해 예를 들어보겠다.



일단 네모의 규칙은 각 마주보는 모서리의 길이는 서로 같다는 것이다.

그러면 아래와 같이 각각 영역을 나눌 수 있는데, 이 때 겹치는 곳이 2 곳 있다.



자 그 영역 중, 한 곳만 생각을 해보겠다.



각각 가로와 세로의 길이를 더하면 겹치는 곳 1곳이 생긴다.

겹치는 곳 중 가로 혹은 세로 한 곳을 빼면 이런 형태가 될 텐데



여기서 다른 나머지 곳도 빼면, 딱 반대 쪽의 개수와 같아진다!



그래서 공식은 (가로 - 1 + 세로 - 1) * 2 가 될 수 있는 것이다.

자! 이제 공식을 이용해서 구했으니 우리는 이 하나의 공식을 이용해서 가로와 세로의 길이를 유추할 수 있다.

하지만 아직 식 하나가 더 필요하다.

그 공식은 안에 있는 노랑색을 이용하는 것이다.

노랑색의 개수는 (가로 * 세로) 즉, 네모의 넓이를 구한 후 brown을 빼면 나온다.

우리는 이렇게 총 2개의 공식을 얻을 수 있다.

[w는 가로 h는 세로]

wh - brown = yellow
(w-1 + h-1) * 2 = brown

이제 2중 for문을 이용하여 가로와 세로의 길이를 구한다.

이때 가로 세로 길이는 무조건 3 이상이 될 수 밖에 없으므로 3 부터 시작한다.

하지만 이 방법의 단점은 2중 for문을 이용하므로 시간 복잡도가 n^2 이 든다는 점이다.

이것보다 더 뛰어난 성능을 할 수 있는 방법이 있다.

그것은 아래와 같은 방법이다.

방법2 Yellow 사용하여 둘레로 접근

Yellow 와 붙어 있는 Brown의 개수는 총 Brown - 4 개와 같다.

이유는 아래 그림과 같이 알 수 있다.



그러면 Yellow 줄 기준(약수)으로 생각할 수 있다.

만약 Yellow 가 4일 경우 Yellow는 2x2, 4x1의 경우가 나온다.

즉 1줄 혹은 2줄로 표현 할 수 있는 것이다.
(약수 개)

반복문을 돌리면 세로 혹은 가로의 개수를 알 수 있다.

반복문의 Yellow개수의 약수로만 가능하므로 반복문 순회 범위는 Yellow개수 ** 0.5 + 1 만큼만 하겠다.

반복문에서 사용할 순회는 “세로”로 기준을 잡아보자!

만약에 Yellow개수 가 나누어 떨어지면, 반복문에 사용한 i 를 “세로”라고 하면 Yellow개수 / i 를 하면 “가로”가 된다.

우리는 가로와 세로의 길이를 구했다.



뭔가 보이지 않는가???

Yellow 가로 * 2 + Yellow 세로 * 2 = 주변의 Brown 개수와 같다!



그러면 공식은

(i + Yellow개수/i) * 2 == Brown - 4(주변뺌) 가 가능하다

i = 세로 개수
Yellow개수 / i = 가로 개수

이 공식에 적절한 가로, 세로를 구한다.

그 후, Yellow의 가로와 세로를 정확하게 구했으니 주변에 Brown이 둘러싸고 있으니 가로 + 2, 세로 + 2 하면 답이 나온다.



이걸 생각한 사람은 진짜 대단한 것 같다……… 존경


코드 방법 1

def solution(brown, yellow):
    for w in range(3, brown):
        for h in range(3, brown):
            if (w + h - 2) * 2 == brown and w*h-brown== yellow:
                return ([max(w,h), min(w,h)])

코드 방법 2

def solution(brown, yellow):
    for i in range(1, int(yellow**(1/2))+1):
        if yellow % i == 0:
            if 2*(i + yellow//i) == brown-4:
                return [yellow//i+2, i+2]

댓글남기기