2023년 7월 29일 알고리즘 문제풀이
백준 13334번
1차 시도
나의 생각
사람들의 사무실 과 집 둘 중 좌표가 작은 것을 먼저 오게 한 후, 그것을 오름차순으로 배열에 정리하였다. 각 지점을 철로의 시작점으로 삼아 모든 case를 검사하며 최댓값을 업데이트했다. 다 검사해버리니 당연히 시간초과…
결과
오답
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
from heapq import heappop, heappush
n = int(sys.stdin.readline())
people = []
for _ in range(n):
h,o = map(int,sys.stdin.readline().split())
if h <= o:
heappush(people,[h,o])
else:
heappush(people,[o,h])
d = int(sys.stdin.readline())
ans = 0
while people:
cnt = 0
x = people[0][0]
for person in people:
if person[0] >= x and person[1] <= x+d:
cnt += 1
ans = max(ans,cnt)
heappop(people)
print(ans)
2차 시도
나의 생각
어떤 사람의 집과 사무실의 거리는 철로의 길이인 d보다 멀 수도있다. 이 사람은 철로를 어디에 설정하든 이용할 수 없다. 따라서 입력을 받을 때 이런 케이스를 지우려고 했다. 또한 정렬을 해버린 만큼 굳이 필요하지 않은 조건들도 제거하였다. 하지만 예외케이스가 있는지 오답처리되었다.
결과
오답
코드
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
import sys
from heapq import heappop, heappush
n = int(sys.stdin.readline())
tmp_people = []
people = []
for _ in range(n):
h,o = map(int,sys.stdin.readline().split())
if h <= o:
tmp_people.append([h,o])
else:
tmp_people.append([o,h])
d = int(sys.stdin.readline())
for person in tmp_people:
if person[1]-person[0] <= d:
people.append(person)
people.sort(key= lambda x:x[1])
ans = 0
k = len(people)
for i in range(k):
cnt = 0
x = people[i][0]
for j in range(i,k):
if people[j][0] > x+d:
break
if people[j][1] <= x+d:
cnt += 1
ans = max(ans,cnt)
print(ans)
3차 시도
나의 생각
다른 사람들의 코드와 설명을 한참 보고도 이해가 힘들었는데 겨우겨우 이해했다..
우선 각 사람들의 집과 오피스를 상관하지 말고 좌표의 크기로만 생각한다. 입력값으로 주어진 좌표들을 담는다. 우선 집과 사무실의 거리가 철로의 거리보다 먼 사람들은 제외한다. 어떠한 경우에도 철로에 포함될 수 없기 떄문이다. 각 사람의 집과 사무실 좌표를 좌표 크기에 따라 오름차순 정렬한 후, 전체 배열을 왼쪽좌표의 오름차순으로 정렬한다. 같은 것들은 오른쪽 좌표를 기준으로 오름차순으로 정렬하였다.
핵심은 배열에 있는 각 사람의 오른쪽 점을 철로의 끝으로 생각하는 것이다.
정렬된 배열의 첫번째 사람의 오른쪽 점을 현재 철로의 끝점으로 생각한다. 아래 코드에서 x[1]
이 이 점을 의미한다. x[1]-d
는 철로의 끝점에서 철로의 길이만큼 뺸 것이니 철로의 시작점을 의미한다. 사람들을 heap에 담는 과정에서, 최소 힙이므로 최솟값이 0을 index로 하는 원소가 된다. 정확히는 왼쪽좌표가 가장 작은사람이다. x[1]-d
로 구한 철로의 시작점보다 더 작은 좌표값을 왼쪽 점으로 가지는 사람은 더이상 철로에 포함되지 않는 사람이므로 heap에서 제거해야한다. 각 사람의 오른쪽 점을 철로의 끝점으로 삼고 사람을 옮겨가면서 현재 철로에 포함된 사람이자 heap에 들어있는 사람중 왼쪽 점이 최소인 사람을 조사해 이 사람이 철로에 포함되는지 검사하는 것이다. 포함되지 않는다면 제거하고 그 다음 최솟값으로 설정된 사람을 조사하면 된다. 포함된다면? 더이상 조사할 필요가 없다. 왼쪽점의 오름차순으로 정렬되어있으므로 당연히 다음 원소들은 철로에 포함되는 사람들일 것이다. 혹여나 이해가 힘든 사람들을 위해 마지막 최댓값을 구하는 과정을 조금 더 간결하게 정리해보겠다.
- 모든 사람은 집과 사무실을 가진다. 하지만 이제부터 왼쪽 점과 오른쪽 점을 가진다고 생각하자. 그게 집이든 사무실이든 상관없다.
- 왼쪽 점과 오른쪽 점의 거리가 철로보다 긴 사람들도 있을 수 있다. 그 사람들이 철로안에 두 점을 모두 포함시킬 방법은 없다.
- 따라서 우선적으로 배열에서 제거한다.
- 배열에 남은 사람들을 우선 왼쪽점의 좌표를 기준으로 오름차순 정렬하고, 왼쪽 점이 같다면 오른쪽 점을 기준으로 오름차순 정렬한다.
- 배열된 사람들을 하나씩 주목한다. 이는 검사를 위해서가 아니라 철로의 설정을 위해서이다. 검사를 위해 heap 배열을 새로 만든다.
- 주목한 사람의 오른쪽 점을 철로의 끝으로 설정한다. 그리고 주목한 사람은 heap 배열에 넣는다.
- heap 배열의 0번 index는 최솟값이 와야한다. 그말은 왼쪽 좌표의 값이 가장 작은 사람이라는 뜻이다.
- 지금 주목한 사람의 오른쪽 점은 철도의 끝점이다. 그럼 철도의 시작점은 이 점에서 철도의 길이인
d
를 뺴면 된다. - heap의 최솟값과 철도의 시작점을 비교한다. 최솟값이 더 작다면 제거한다. 철도밖에 왼쪽 점이 있다는 뜻이기 떄문이다.
- 이 검사를 heap 내에 있는 모든 사람을 대상으로 검사한다.
- 결국 heap에는 철도에 포함되는 사람들의 수만 남게 된다. 이 수를 최댓값과 비교하며 업데이트한다.
- 왼쪽 점이 철도에 포함된다면 heap에서 빠지지 않는다. 철도의 끝점이 바뀌어도 heap에 남게된다.
결과
이해 완료
코드
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
29
30
31
32
import sys
from heapq import heappush, heappop
n = int(sys.stdin.readline())
people = []
for _ in range(n):
person = list(map(int, sys.stdin.readline().split()))
people.append(person)
d = int(sys.stdin.readline())
arr = []
for person in people:
house, office = person
if abs(house - office) <= d:
person = sorted(person)
arr.append(person)
arr.sort(key=lambda x:x[1])
ans = 0
heap = []
for x in arr:
if not heap:
heappush(heap, x)
else:
while heap[0][0] < x[1] - d:
heappop(heap)
if not heap:
break
heappush(heap, x)
ans = max(ans, len(heap))
print(ans)
백준 1715
1차 시도
나의 생각
쉬운 문제인듯 했으나 규칙을 잘못파악해서 오래걸렸다. 나는 카드 더미중 가장 작은 두개를 더한 다음, 차례차례 그 다음으로 작은 값을 더해주면 된다고 생각했다. 그래서 두개를 더한 후 그 값을 2배한 뒤 그 다음 작은 값을 heappop
하여 더해주는 방법을 이용했으나 틀렸다. 안되는 이유는 예시를 통해 금방 알 수 있다.
카드 더미가 10 20 15 21 40 으로 이루어진 5개라고 생각해보자. 기존의 내 코드에 의하면
- 10 + 15 = 25
- 25 * 2 = 50
- 50 + 20 = 70
- 70 * 2 = 140
- 140 + 21 = 161
- 161 * 2 = 322
- 322 + 40 = 362 이라는 결과가 도출된다. 실제 정답과의 차이는 2번에서 발생한다.
10과 15를 더하여 25라는 비교 횟수를 구하고 나면 카드더미는 25,20,21,40 4개가 된다.
애초에 문제를 이렇게 4개짜리를 받았다면 내 로직으로는 당연히 20과 21을 더하면서 시작해야한다.
근데 내 첫 로직은 25와 20을 더한다! 처음 더미를 합친 25에 25+20을 더해서 70을 도출한 결과가 3번이다. 여기서 문제가 발생하여 오답이였다. 따라서 현재 카드 더미중 가장 작은 두개의 값을 더한 후 다시 배열에 넣어 가장 작은 2개를 새롭게 찾아내야 한다.
결과
정답
코드
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
import sys
from heapq import heappop, heappush
n = int(sys.stdin.readline())
cards = []
for _ in range(n):
card = int(sys.stdin.readline())
heappush(cards,card)
cnt = 0
ans = 0
if n == 1:
ans = 0
elif n == 2:
tmp1 = heappop(cards)
tmp2 = heappop(cards)
ans = tmp1 + tmp2
else:
while len(cards) > 1:
tmp1 = heappop(cards)
tmp2 = heappop(cards)
tmp = tmp1 + tmp2
ans += tmp
heappush(cards,tmp)
ans += heappop(cards)
print(ans)