Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 소프티어
- 소프티어부트캠프
- 우분투22.04
- 그리디알고리즘
- 피보나치수
- 표준입력
- Python
- docker
- open(0)
- zshrc
- 백준
- code golf
- 데이터엔지니어
- 파이썬
- IDA*
- 데이터엔지니어링
- 대학생알고리즘특강
- hmg소프티어부트캠프
- 현대자동차
- 알고리즘특강
- 에라토스테네스의채
- 실전sql퀵스타트
- 현대자동차그룹
- spaghetti code
- 윈도우클린설치
- 비트집합
- Short Coding
- ucpc
- boj
- 도커
Archives
- Today
- Total
Neo Ground
[백준 | Python] #16209 - 수열 섞기 본문
16209번: 수열 섞기
인접한 원소의 곱들을 최대화한 본 수열의 재배열을 하나 출력하자. 만약 최대화할 수 있는 재배열이 여러 가지 있다면 아무거나 하나 출력하면 된다.
www.acmicpc.net
문제
길이가 $N$인 수열 $a_1,…,a_N$을 재배열 했을 때 인접한 원소의 곱들의 합, 즉 $a_1a_2+a_2a_3+…a_{N-1}a_N$이 최대일 때의 재배열 된 수열을 출력하여라.
아이디어
직관적으로 절댓값이 큰 수부터 서로 곱해야 합을 최대로 만들 수 있음을 알 수 있다.
양수는 양수끼리, 음수는 음수끼리 곱하여 최대한 많은 곱을 양수로 만들어야 한다.
0은 최대한 0끼리 곱하고 부득이한 경우 절댓값이 가장 작은 수와 곱한다.
구현
- 주어진 수열을 정렬한 후 음수, 0, 양수 부분으로 분리한다.
- 음수, 양수 부분은 절댓값이 큰 수부터 차례로 다음의 규칙을 통해 각각의 양방향 큐(deque)에 추가한다.
1) 첫 번째 수와 두 번째 수는 그냥 추가
2) 이후로는 양방향 큐의 양쪽 끝 원소 중 절댓값이 큰 쪽에 추가 - 0이 포함된 배열의 양쪽에 앞서 만든 두 개의 양방향 큐를 연결하여 출력한다.
단, 0과 연결되는 쪽은 절댓값이 더 작은 수로 한다.
문제를 해결한 후 생각해보니 2번은 더 간단하게 구현할 수 있었다.
분리된 수열에서 짝수 번째와 홀수 번째를 분리하여 절댓값이 큰 수를 중앙으로 하여 분리된 두 배열을 연결하면 간단하게 해결된다… 양방향 큐도 필요 없다.
그래도 그리디 알고리즘을 굳이 직접 구현했음에 의의를 두는 것이 좋을 것 같다.
코드
원래 떠올렸던 아이디어로 작성한 코드는 아래와 같다.
from collections import deque
n = int(input())
nums = list(map(int, input().split()))
nums.sort() # 오름차순 정렬
negative = deque()
zero = deque()
positive = deque()
# 원소가 음수일 때까지 절댓값이 큰 수부터 음수 양방향 큐에 추가
i = 0
while i < n and nums[i] < 0:
if len(negative) < 2 or negative[0] > negative[-1]:
negative.append(nums[i])
else:
negative.appendleft(nums[i])
i += 1
# 원소가 0이면 단순히 zero 배열에 추가
while i < n and nums[i] == 0:
zero.append(0)
i += 1
# 원소가 양수일 때까지 절댓값이 큰 수부터 양수 양방향 큐에 추가
j = n-1
while j >= i:
if len(positive) < 2 or positive[0] < positive[-1]:
positive.append(nums[j])
else:
positive.appendleft(nums[j])
j -= 1
ans = [] # 최종 출력 리스트
# 절댓값이 작은 수를 가운데로 하여 음수 양방향 큐 추가
if len(negative) < 2 or negative[0] < negative[-1]:
ans += negative
else:
ans += reversed(negative)
ans += zero
# 절댓값이 작은 수를 가운데로 하여 양수 양방향 큐 추가
if len(positive) < 2 or positive[0] < positive[-1]:
ans += positive
else:
ans += reversed(positive)
print(*ans)
간단한 구현으로 정돈된 코드는 아래와 같다.
n = int(input())
nums = list(map(int, input().split()))
nums.sort()
# 음수
neg_idx = 0
while neg_idx < n and nums[neg_idx] < 0: neg_idx += 1
negative = nums[0:neg_idx:2][::-1] + nums[1:neg_idx:2]
# 양수
pos_idx = n-1
while pos_idx >= 0 and nums[pos_idx] > 0: pos_idx -= 1
positive = nums[pos_idx+1:n:2] + nums[pos_idx+2:n:2][::-1]
# 0
zero = [0] * (pos_idx - neg_idx + 1)
if negative and negative[0] > negative[-1]:
negative.reverse()
if positive and positive[0] > positive[-1]:
positive.reverse()
print(*(negative + zero + positive))
번외) 숏코딩
N,*n=map(int,open(0).read().split())
n.sort()
x=len(a:=[i for i in n if i<0])
y=len(b:=[i for i in n if i>0])
print(*((a[-1-x%2::-2]+a[::2])[::x%2*2-1]+[0]*(N-x-y)+(b[y%2::2]+b[::-2])[::1-y%2*2]))
더 줄일 수 있을 것 같지만 머리가 아프다.
'Problem Solving' 카테고리의 다른 글
[백준 | Python] #11444 - 피보나치 수 (cache decorator) (1) | 2023.11.18 |
---|---|
[백준 | Python] #2549 - 루빅의 사각형 (IDA* 알고리즘) (0) | 2023.08.28 |
백준 파이썬 숏코딩 팁 (Python Code Golf) (0) | 2023.08.26 |
[백준 | Python] #11967 - 불켜기 (0) | 2023.07.26 |
[백준 | Python] #9363 - 큰 나눗셈 (0) | 2023.07.25 |