새소식

PS/백준

[백준/13334] 철로 (Python)

  • -

Problem : https://www.acmicpc.net/problem/13334

 

13334번: 철로

입력은 표준입력을 사용한다. 첫 번째 줄에 사람 수를 나타내는 양의 정수 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 각 줄에 정수 쌍 (hi, oi)가 주어진다. 여기서 hi와 oi는 −100,000,000이상, 100,000,0

www.acmicpc.net

 

Difficulty : Gold 2

 

Status : Solved

 

Time : 00:41:13

 


 

문제 설명

 

더보기

집과 사무실을 통근하는 n명의 사람들이 있다. 각 사람의 집과 사무실은 수평선 상에 있는 서로 다른 점에 위치하고 있다. 임의의 두 사람 A, B에 대하여, A의 집 혹은 사무실의 위치가 B의 집 혹은 사무실의 위치와 같을 수 있다. 통근을 하는 사람들의 편의를 위하여 일직선 상의 어떤 두 점을 잇는 철로를 건설하여, 기차를 운행하려고 한다. 제한된 예산 때문에, 철로의 길이는 d로 정해져 있다. 집과 사무실의 위치 모두 철로 선분에 포함되는 사람들의 수가 최대가 되도록, 철로 선분을 정하고자 한다.

양의 정수 d와 n 개의 정수쌍, (hi, oi), 1 ≤ i ≤ n,이 주어져 있다. 여기서 hi와 oi는 사람 i의 집과 사무실의 위치이다. 길이 d의 모든 선분 L에 대하여, 집과 사무실의 위치가 모두 L에 포함되는 사람들의 최대 수를 구하는 프로그램을 작성하시오.

그림 1 에 있는 예를 고려해보자. 여기서 n = 8, (h1, o1) = (5, 40), (h2, o2) = (35, 25), (h3, o3) = (10, 20), (h4, o4) = (10, 25), (h5, o5) = (30, 50), (h6, o6) = (50, 60), (h7, o7) = (30, 25), (h8, o8) = (80, 100)이고, d = 30이다. 이 예에서, 위치 10 과 40 사이의 빨간색 선분 L이, 가장 많은 사람들에 대하여 집과 사무실 위치 모두 포함되는 선분 중 하나이다. 따라서 답은 4 이다.

 

입력 및 출력

 

더보기

입력

입력은 표준입력을 사용한다. 첫 번째 줄에 사람 수를 나타내는 양의 정수 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 각 줄에 정수 쌍 (hi, oi)가 주어진다. 여기서 hi와 oi는 −100,000,000이상, 100,000,000이하의 서로 다른 정수이다. 마지막 줄에, 철로의 길이를 나타내는 정수 d (1 ≤ d ≤ 200,000,000)가 주어진다.

 

출력

출력은 표준출력을 사용한다. 길이 d의 임의의 선분에 대하여, 집과 사무실 위치가 모두 그 선분에 포함되는 사람들의 최대 수를 한 줄에 출력한다. 

 

입력 예시

8
5 40
35 25
10 20
10 25
30 50
50 60
30 25
80 100
30

 

출력 예시

4

 

 


 

풀이

 

라인 스위핑 문제의 변종이라고 볼 수 있다. 또다른 변종 문제를 한 번 보도록 하자.

 

2023.03.16 - [알고리즘 문제/백준] - [백준/10165] 버스 노선 (Python)

 

[백준/10165] 버스 노선 (Python)

Problem : https://www.acmicpc.net/problem/10165 10165번: 버스 노선 첫 번째 줄에는 버스 정류소의 개수 N(3 ≤ N ≤ 1,000,000,000)이 주어지고 두 번째 줄에는 버스 노선의 수 M(2 ≤ M ≤ 500,000)이 주어진다. 각 버

magentino.tistory.com

 

리스트를 정렬하고, 리스트를 단 한 번 순회하며 최댓값을 찾는다는 핵심은 비슷하다. 차이점은 우리가 구하고자 하는 최대가 '일정 길이 안에 포함되는 선분 개수의 최댓값'이라는 점이다.

 

선분의 길이를 잴 때, 시작점 < 끝점인 상황을 가정하면 그 길이는 (끝점 - 시작점)이다. 이 문제를 풀기 위해 조건에 해당하는 선분을 리스트에 집어넣는다고 가정하자. 리스트를 하나의 큰 선으로 생각한다면, 리스트의 실질적인 길이는 (끝점의 최댓값 - 시작점의 최솟값)이 될 것이다. 이 말인 즉슨, 리스트에 선분을 넣을 때마다 변동할 수 있는 시작점의 최솟값, 혹은 끝점의 최댓값을 우리가 기억하고 있어야 한다는 의미이다. 이럴 때 사용할 수 있는 자료구조로 우선순위 큐가 있다. 우선순위 큐의 삽입과 삭제는 O(logN)이 소요되므로 충분한 시간복잡도 내에 항상 우리가 원하는 값을 제거할 수 있다.

 

  • 선분 리스트를 (끝점, 시작점)기준으로 오름차순 정렬한다.
  • 선분을 순회하며, 다음과 같은 과정을 거친한다.
    • 우선순위 큐에 선분을 삽입한다. 여기서 우선순위는 (시작점, 끝점)이 되어야 한다.
    • 우선순위 큐의 '선분 길이', 그러니까 (끝점의 최댓값 - 시작점의 최솟값)은 항상 d 이하여야 한다. 앞선 정렬에 의해 앞서 삽입한 끝점은 끝점의 최댓값임이 보장된다(오름차순이므로), '선분 길이'가 d 이하가 될때까지, 우선순위 큐의 원소 삭제를 시행한다.
    • 큐의 원소 개수(큐의 길이)를 최댓값과 비교하여 업데이트한다
  • 순회가 끝나면 최댓값을 반환한다.

 

이에 따라 총 O(NlogN)의 시간복잡도 내에 풀이 가능하다!

 

 

풀이 코드

from heapq import *
import sys
input = sys.stdin.readline

def init() :
  n = int(input())
  line_list = list()
  
  for _ in range(n) :
    h, o = map(int, input().split())
    if h > o :
      h, o = o, h
    line_list.append((h, o))

  line_list.sort(key = lambda x : (x[1], x[0]))
  d = int(input())

  return line_list, d

def traversal(line_list, d) :
  q = []
  result = 0
  
  for h, o in line_list :
    if o - h > d :
      continue

    heappush(q, (h, o))

    while o - q[0][0] > d :
      heappop(q)

    result = max(result, len(q))
    print(h, o, q)

  return result

def solve() :
  line_list, d = init()
  result = traversal(line_list, d)

  print(result)

solve()

풀이 완료~

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.