코테 공부/그 외 사이트

[Python/그리디] 3.직사각형 만들기

prefer_all 2022. 11. 30. 09:27

출처: 구름 알고리즘 먼데이 챌린지 8주차

문제

구름이는 N개의 직선 막대기를 가지고 있다. 구름이는 이 막대기들 중 일부를 잘 배치해서, 직사각형을 만들고자 한다.

직사각형을 만들기 위해서는 길이가 같은 막대기 두 쌍이 필요하다. 같은 쌍에 속한 막대기들을 마주 보게 배치하고, 다른 쌍에 속한 막대기들을 수직으로 배치하면 아래 그림과 같이 직사각형을 만들 수 있다. 길이가 a인 막대기와 길이가 b인 막대기 쌍을 사용해서 직사각형을 만들었을 때, 만들어진 직사각형의 넓이는 ab이다.



하나의 막대기는 하나의 직사각형을 만드는 데만 이용할 수 있고, 구름이는 가능한 많은 직사각형을 만들면서도 직사각형들의 넓이 합이 최대가 되기를 원한다. 구름이가 가지고 있는 막대기의 정보가 주어졌을 때, 구름이가 만들 수 있는 직사각형들의 넓이 합의 최댓값을 구하시오.


입력

첫째 줄에는 구름이가 가지고 있는 막대기의 개수를 의미하는 정수 N(1<=N<=10^6) 이 주어진다.

둘째 줄에는 N개의 정수가 공백으로 구분되어 주어진다. 각 정수는 구름이가 가지고 있는 막대기의 길이를 의미하고, 모든 막대기의 길이는  1 이상  10^6 이하이다.

 

출력

구름이가 만들 수 있는 직사각형들의 넓이 합의 최댓값을 출력하시오.

 

예제 입력 예제 출력
4
4 8 4 8
32
8
2 4 6 8 2 4 6 8
56
5
1 2 3 4 5
0


풀이

최적의 전략을 맞아서 문제를 해결하는 그리디(greedy) 알고리즘 문제이다.

1. 일단 a라는 막대기 하나인 경우에는 직사각형을 만들 수 없으므로 무시하고,

a 막대기가 3 이상의 홀수 개인 경우 짝수개로 취급을 해준다.

 

2. a,b,c,d 네 개의 막대기가 있고 a <= b <= c <= d 인 경우,

a*b + c*d일 때 넓이의 최댓값이다.

따라서 막대기 쌍의 길이가 긴 것부터 순서대로 직사각형을 만들어주면 된다.

 

1번이 구현하기 까다로웠는데 collections의 Counter를 사용해서

value가 2 이상일 때까지만 counter에서 value를 2개씩 빼면서, 처리된 막대기쌍을 담는 리스트 pair에 key를 append했다.

'''
N개의 직선 막대기. 네 개의 막대기로 하나의 직사각형을 만든다.
막대기를 가지고 만들 수 있는 직사각형 넓이의 합이 최대가 되게
같은 직선이 모두 2개씩이 아니라면?
'''
from collections import Counter
import sys
input = sys.stdin.readline

N = int(input())
lines = list(map(int, input().split()))

# 1. 막대기 쌍 처리
pair = [] # lines 후처리 (1, 홀수 처리)
counter = Counter(lines)
#print(counter)
for line in counter.keys():
	while counter[line] > 1:
		counter[line] -= 2
		pair.append(line)
#print(pair)

# 2. 직사각형들 넓이 계산
pair.sort(reverse=True)
ans = 0
for i in range(0, len(pair)-1, 2):
    ans += pair[i] * pair[i+1]

print(ans)

다른 풀이

Counter를 직접 구현한 경우

import sys
input = sys.stdin.readline

N = int(input())
lines = list(map(int, input().split()))

# 1. 막대기 쌍 처리
pair = [] # lines 후처리 (1, 홀수 처리)
length = max(lines)
counter = [0 for _ in range(length+1)]
for line in lines:
	counter[line] +=1
#print(counter)

for line in range(len(counter)):
	while counter[line] > 1:
		counter[line] -= 2
		pair.append(line)
#print(pair)

# 2. 직사각형들 넓이 계산
pair.sort(reverse=True)
ans = 0
for i in range(0, len(pair)-1, 2):
    ans += pair[i] * pair[i+1]

print(ans)