알고리즘/백준

2170번 : 선 긋기

코딍코딍 2023. 9. 10. 19:33

https://www.acmicpc.net/problem/2170

 

2170번: 선 긋기

첫째 줄에 선을 그은 횟수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y (-1,000,000,000 ≤ x < y ≤ 1,000,000,000)가 주어진다.

www.acmicpc.net

 

문제

매우 큰 도화지에 자를 대고 선을 그으려고 한다. 선을 그을 때에는 자의 한 점에서 다른 한 점까지 긋게 된다. 선을 그을 때에는 이미 선이 있는 위치에 겹쳐서 그릴 수도 있는데, 여러 번 그은 곳과 한 번 그은 곳의 차이를 구별할 수 없다고 하자.

이와 같은 식으로 선을 그었을 , 그려진 ()의 총 길이를 구하는 프로그램을 작성하시오. 선이 여러 그려진 곳은 번씩만 계산한다.

 

입력

첫째 줄에 선을 그은 횟수 N (1 ≤ N ≤ 1,000,000) 주어진다. 다음 N개의 줄에는 선을 그을 선택한 점의 위치 x, y (-1,000,000,000 ≤ x < y ≤ 1,000,000,000) 주어진다.

 

출력

첫째 줄에 그은 선의 총 길이를 출력한다.

 


소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int arr[][] = new int[n][2];
        for (int i = 0; i < n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine(), " ");
            arr[i][0] = Integer.parseInt(st.nextToken());
            arr[i][1] = Integer.parseInt(st.nextToken());
        }

        // sorting
        Arrays.sort(arr, new Comparator<int[]> () {
            @Override
            public int compare(int[] o1, int[] o2) {
                if(o1[0] == o2[0]) {
                    return o1[1] - o2[1];
                } else return o1[0] - o2[0];
            }
        });

        long result = 0;
        int s = arr[0][0]; // 기존 선 시작점
        int e = arr[0][1]; // 기존 선 끝점
        for (int i = 1; i < n; i++) {
            int ns = arr[i][0]; // 현재 선 시작점
            int ne = arr[i][1]; // 현재 선 끝점
            
            // 연장
            if(s <= ns && ns <= e) {
                if(e < ne) e = ne;
            }
            // 포함
            else if(s <= ns && ne <= e) {
                continue;
            }
            // 새로운 선
            else {
                result += (Math.abs(e - s)); // 기존 선 길이 계산
                s = ns;
                e = ne;
            }
        }

        result += (Math.abs(e - s)); // 마지막 선 길이 계산
        System.out.println(result);
    }
}

 

해결방법

정렬 + 스위핑 알고리즘을 사용하여 문제를 해결했다.

문제는 의외로 간단하다. 먼저 시작점과 끝점 기준으로 정렬을 해준다. 그러면 시작점이 가장 작은 선부터 순서대로 배열에 정렬된다.

 

배열에 저장된 모든 선을 탐색하면서 아래 세 가지 경우만 판단하면 된다.

1) 선분이 새로 시작되는 경우

2) 선분이 연장되는 경우

3) 선분이 기존에 그렸던 선분에 완전히 포함되는 경우

 

세 가지 경우를 판단하여 코드를 구현하면 쉽게 해결할 수 있다.