문제
문제 설명
명함 지갑을 만드는 회사에서 지갑의 크기를 정하려고 합니다. 다양한 모양과 크기의 명함들을 모두 수납할 수 있으면서, 작아서 들고 다니기 편한 지갑을 만들어야 합니다. 이러한 요건을 만족하는 지갑을 만들기 위해 디자인팀은 모든 명함의 가로 길이와 세로 길이를 조사했습니다.
아래 표는 4가지 명함의 가로 길이와 세로 길이를 나타냅니다.
| 명함 번호 | 가로 길이 | 세로 길이 |
| 1 | 60 | 50 |
| 2 | 30 | 70 |
| 3 | 60 | 30 |
| 4 | 80 | 40 |
가장 긴 가로 길이와 세로 길이가 각각 80, 70이기 때문에 80(가로) x 70(세로) 크기의 지갑을 만들면 모든 명함들을 수납할 수 있습니다. 하지만 2번 명함을 가로로 눕혀 수납한다면 80(가로) x 50(세로) 크기의 지갑으로 모든 명함들을 수납할 수 있습니다. 이때의 지갑 크기는 4000(=80 x 50)입니다.
모든 명함의 가로 길이와 세로 길이를 나타내는 2차원 배열 sizes가 매개변수로 주어집니다. 모든 명함을 수납할 수 있는 가장 작은 지갑을 만들 때, 지갑의 크기를 return 하도록 solution 함수를 완성해주세요.
제한사항
- sizes의 길이는 1 이상 10,000 이하입니다.
입출력 예
| sizes | result |
| [[60, 50], [30, 70], [60, 30], [80, 40]] | 4000 |
| [[10, 7], [12, 3], [8, 15], [14, 7], [5, 15]] | 120 |
| [[14, 4], [19, 6], [6, 16], [18, 7], [7, 11]] | 133 |
입출력 예 #1
문제 예시와 같습니다.
입출력 예 #2
명함들을 적절히 회전시켜 겹쳤을 때, 3번째 명함(가로: 8, 세로: 15)이 다른 모든 명함보다 크기가 큽니다. 따라서 지갑의 크기는 3번째 명함의 크기와 같으며, 120(=8 x 15)을 return 합니다.
입출력 예 #3
명함들을 적절히 회전시켜 겹쳤을 때, 모든 명함을 포함하는 가장 작은 지갑의 크기는 133(=19 x 7)입니다.
문제 풀이
처음 문제를 봤을 땐 케이스에 따라 나눠가면서 풀어야한다고 생각하고 코드를 짜다가 많은 반례를 만났다.
분명 프로그래머스 Lv.1인데 DP문제인가..? 하는 고민도 하였다.
다시 생각해보니 직사각형의 넓이가 최소화되기 위해서는
양 변의 길이가 길어지는 것보다 한 변의 길이만 길어지는 것이 이득임을 기억했다.
우리가 두 변의 길이가 10이 되도록하는 직사각형의 넓이들은
1 x 9, 9 x 1 = 9
2 x 8, 8 x 2 = 16
...
5 x 5 = 25
양 변의 길이 합이 작아질 수록 넓이가 작아지는 것은 자명하고
두 변의 합의 길이가 고정됐을 때 두 변의 길이가 같다면 넓이가 가장 큰 것을 알 수 있는데 증명하자면
- x와 y가 가로 세로 변일 때, x + y = z 이며 z는 고정 값이라고 가정
- 두 변의 넓이는 x * y로 x * (z - x)와 같다. 풀어 쓰게되면 (zx - x2) 이며
- 이 함수는 위로 볼록한 형태를 가지고 있으므로 최대값을 가지고 미분하여 0되는 지점 (기울기가 0인지점)에서 최대값을 가진다.
- 미분하면 z - 2x이며 x = z/2 인 부분에서 최대값을 가진다. 즉 x,y가 값이 같을 수록 값이 커지고 차이가 클 수록 작은 값이 됨을 알 수 있다.
따라서 한 변은 최소값을 가지도록 하고 한 변은 최대값을 가지도록 하여 두 변의 차이가 크게 만들면 정답을 찾을 수 있다.
코 드
처음에 C++이 아직 익숙해 C++ 형식으로 코드를 짰다.
def solution(sizes):
w, h = 0, 0
for size in sizes:
width, height = max(size[0], size[1]), min(size[0], size[1])
w = max(width, w)
h = max(height, h)
return w * h
이후 다른 사람들의 풀이를 보며 정리한 코드는 아래와 같다. 결국 위 아래 코드 모두 같은 역할이다.
def solution(sizes):
answer = max(max(x) for x in sizes) * max(min(x) for x in sizes)
return answer
느낀점: 파이썬은 참 다양한 것을 모듈화해놨다.. 적응하기까지 시간이 걸릴 것 같다.
그리고 그리디는 참 증명이 어렵고 탐욕법인지 보고 아직까지 바로 알아채지 못하는게 아쉽다.
링크: https://school.programmers.co.kr/learn/courses/30/lessons/86491
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
'Problem Solving > 프로그래머스' 카테고리의 다른 글
| [프로그래머스/C++] 단속카메라 풀이 (greedy를 스마트하게) (0) | 2023.05.08 |
|---|---|
| [프로그래머스/약수 찾기] 약수의 개수와 덧셈 (나를 위한 기록) (0) | 2023.04.28 |
| [프로그래머스/파이썬] 2018 KAKAO BLIND RECRUITMENT[1차] 비밀지도 (0) | 2023.04.24 |
| [프로그래머스/파이썬] 성격 유형 검사하기 (0) | 2023.04.20 |
| [프로그래머스/C++] 달리기 경주 풀이 (0) | 2023.04.17 |