문제 정보

풀이

전깃줄이 교차하지 않도록 없애야 하는 전깃줄의 최소 개수를 구하는 문제로, LIS 응용 문제다.

우선 전깃줄이 언제 교차하는지부터 생각해보자.

전깃줄 가 있다고 할 때, 또는 이면 두 전깃줄 는 교차하는 전깃줄이다.

즉 **전깃줄이 교차하지 않으려면 일 때 **이어야 한다.

A 전봇대를 기준으로 오름차순 정렬하면 가 보장된다. 이제 B값만 놓고 봤을 때, 순서가 증가하는 전깃줄끼리는 교차하지 않는다.

즉, ==교차하지 않는 전깃줄의 최대 개수== = 을 만족하는 수열의 길이, 다시 말해 ==B값의 LIS==가 된다.

A 기준 정렬 후 B 기준 LIS를 구하는 것이므로, A 순서도 오름차순이고 B 순서도 오름차순인 전깃줄의 최대 집합을 구하는 것과 같다. 이 집합에 속한 전깃줄들은 서로 교차하지 않는다.

최소 제거 개수를 구하기 위해서는 교차하지 않는 전깃줄을 최대한 남기고 나머지를 제거하면 된다. 따라서 답은 N - LIS이다. (LIS가 최대이므로, 제거하는 개수가 최소임이 보장됨.)

코드

import java.io.*;
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[][] wire = new int[n][n];
        for (int i = 0; i < n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            wire[i][0] = Integer.parseInt(st.nextToken());
            wire[i][1] = Integer.parseInt(st.nextToken());
        }
        
        Arrays.sort(wire, (a, b) -> Integer.compare(a[0], b[0]));
        
        int[] dp = new int[n];
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (wire[i][1] > wire[j][1])
                    dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        
        int max = -1;
        for (int i = 0; i < n; i++)
            max = Math.max(max, dp[i]);
        
        System.out.println(n - max);
    }
}

관련 노트