https://school.programmers.co.kr/learn/courses/30/lessons/42842
코딩테스트 연습 > 완전탐색 > 카펫
풀이 : Python
Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다.

Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.
Leo가 본 카펫에서 갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 solution 함수를 작성해주세요.

※ 공지 - 2020년 2월 3일 테스트케이스가 추가되었습니다.
※ 공지 - 2020년 5월 11일 웹접근성을 고려하여 빨간색을 노란색으로 수정하였습니다.
col = 세로
row = 가로
다른것보다 문제의 조건을 정확히 이해하고 접근하는게 가장 중요한 문제이다.
아래의 그림과 같은 경우가 가장 최소한으로 모든 조건을 맞추는 경우이다.

col이 3보다 작은 경우라면 아래의 그림과 같이 갈색이 노란색을 둘러싸을 수 없게 된다.

그렇기 때문에 문제의 조건인 노란색을 둘러 싸기 위해서는 col=3이라는 값을 지켜야만 하는 것이다.
세로 길이 조건 확인 (if total % col == 0:)
total이 col로 나누어 떨어지는지 확인한다.
즉, col이 total의 약수인지 확인하는 것이다. 왜냐하면 col이 total의 약수일 때 col이 가능한 세로의 길이가 되기 때문이다.
가령 brown=8, yellow=1, total=9인 예시 상황에서 col=3이 아니라 col=4가 된다면 사각형이 만들어질 수 없다.

위 그림과 같이 col=4가 된다면 brown=12, yellow=4가 되어야 한다. 반드시 col은 total의 약수가 되어야만 가능한 가로의 길이가 되는 것이다.
정리하자면 total % col == 0이 참이라면, col은 가능한 세로 길이가 된다.
무한 루프 (while True:)
조건 없이 무한 루프를 시작합니다. 적절한 가로와 세로 길이를 찾을 때까지 계속해서 실행된다.
total을 col로 나누어 가로 길이 row를 계산한다.
문제의 상황을 예시로 brown=8, yeloow=1, total=9일 때 row=3, col=3이다.
즉 3 = 9 // 3인것이다.
이외에 brown=12, yellow=4, total=16일 때 row=4, col=4이다.
즉, row = total // col을 만족해야 row 값을 구할 수 있다는 것이다.
만족하지 못 하는 경우를 예로 들자면 brown=8, yellow=1, total=9일 때 row=4,가 된다면 마찬가지로 조건을 만족하는 사각형을 만들 수 없다.
row=4가 된다면 total=16, col=4일때 조건을 만족하는 사각형을 만들 수 있다.
(if ((col - 2) * (row - 2)) == yellow:)
카펫의 내부 노란 타일 영역의 타일 수가 주어진 yellow와 같은지 확인한다.
col - 2는 갈색 타일로 둘러싸인 세로 길이, row - 2는 가로 길이이다.
아래의 그림과 같이 row=4, col=4인 경우라고 할 때, yellow의 넓이는 2 x 2=4 이다.
그렇다면 row와 col을 이용해서 yellow의 넓이를 어떻게 구할 수 있을까? 에 대한 답으로 총 col과 row의 길이를 각 2씩 빼면 된다.
왜냐하면 갈색 타일과 노란색 타일을 모두 합한 큰 사각형의 경우 갈색 타일이 노란색 타일을 한 칸의 크기로 둘러 싼 형태이다.
노란색 타일의 끝에 갈색 타일이 붙어있으므로 갈색 타일을 제거하려면 큰 사각형의 가로와 세로에 1씩 1씩 총 2를 각각 빼주면 된다.

정리하자면 ((col - 2) * (row - 2)) == yellow가 참이라면,
올바른 가로와 세로 길이를 찾은 것이다.
(answer.append(row), answer.append(col), break)
row와 col을 answer 리스트에 추가한다.
break 문을 사용하여 루프를 종료힌다.
(col += 1)
루프가 종료되지 않았다면, 세로 길이 col을 1 증가시켜 다음 가능한 세로 길이를 검사한다.
# 성공한 코드
def solution(brown, yellow):
answer = []
total = brown + yellow
col = 3
while True:
if total % col == 0:
row = total // col
if ((col - 2) * (row - 2)) == yellow:
answer.append(row)
answer.append(col)
break
col += 1
return answer
brown = int(input("brown 개수 : "))
yellow = int(input("yellow 개수 : "))
result = solution(brown, yellow)
print(f"가로 길이: {result[0]}, 세로 길이: {result[1]}")
# 실패한 코드
def solution(brown, yellow):
area_garo = 0
area_sero = 0
all_sum = yellow + brown
all_sum == area_garo * area_sero
area_garo = brown//2 - area_sero + 2
area_sero = brown//2 - area_garo + 2
if area_garo < area_sero :
return 0
return area_garo, area_sero
brown = int(input("brown 개수 : "))
yellow = int(input("yellow 개수 : "))
result = solution(brown, yellow)
print(f"가로 길이: {result[0]}, 세로 길이: {result[1]}")
실패한 코드의 경우 접근 방법이
카펫의 총 격자 수는 brown + yellow이다.
brown 격자의 수는 테두리를 형성하므로, 다음과 같이 계산할 수 있다는 것을 찾았다.
brown=2×가로+2×(세로−2)=2×(가로+세로)−4
이를 활용해서 구하려 했으나 가로길이에 새로길이의 합이 같이 나와서 제대로 구하지 못 했다. yellow를 구하는 식도 찾아야 되는데 그 식을 못 찾고 그냥 brown으로만 구하려고 한게 못 구하게 된 원인이라고 생각한다.
하지만 여러 시도 끝에 성공한 코드를 구현에 성공해서 기분은 좋다.