문제 정보
- 백준 골드 5
- DP
- 문제 링크
풀이
전깃줄이 교차하지 않도록 없애야 하는 전깃줄의 최소 개수를 구하는 문제로, 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);
}
}관련 노트
- 20260210 가장 긴 증가하는 부분 수열: LIS 기본 문제
- 20260211 가장 긴 바이토닉 부분 수열: LIS 응용 문제