와챠의 우당탕탕 코딩 일기장
[백준]동적 계획법1/전깃줄/2565 풀이 JAVA 본문
문제
두 전봇대 A와 B 사이에 하나 둘씩 전깃줄을 추가하다 보니 전깃줄이 서로 교차하는 경우가 발생하였다.
합선의 위험이 있어 이들 중 몇 개의 전깃줄을 없애 전깃줄이 교차하지 않도록 만들려고 한다.
예를 들어, <그림 1>과 같이 전깃줄이 연결되어 있는 경우 A의 1번 위치와 B의 8번 위치를 잇는 전깃줄, A의 3번 위치와 B의 9번 위치를 잇는 전깃줄, A의 4번 위치와 B의 1번 위치를 잇는 전깃줄을 없애면 남아있는 모든 전깃줄이 서로 교차하지 않게 된다.

전깃줄이 전봇대에 연결되는 위치는 전봇대 위에서부터 차례대로 번호가 매겨진다.
전깃줄의 개수와 전깃줄들이 두 전봇대에 연결되는 위치의 번호가 주어질 때,
남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다.
둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.
출력
첫째 줄에 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 출력한다.
풀이(JAVA)
import java.io.*; | |
import java.util.*; | |
/* <전깃줄의 교차를 확인하는 방법> | |
* 전깃줄 1은 1-2, 전긱줄 2는 3-1이라고 하자. | |
* 조건 1, 전깃줄 1이 A전봇대에 연결되는 위치 번호(1) < 전깃줄 2이 A전봇대에 연결되는 위치 번호(3) | |
* 조건 2, 전깃줄 1이 B전봇대에 연결되는 위치 번호(2) > 전깃줄 2이 B전봇대에 연결되는 위치 번호(1) | |
* 조건 1과 조건 2를 모두 만족시키면 전깃줄 1과 2는 서로 교차함! | |
*/ | |
public class Main { | |
static int[][] wire; // 입력받을 N개의 전깃줄 배열 | |
static int[] dp; // dp[n] = m; n번째 전깃줄을 설치하면 최대 m만큼의 전깃줄을 교차없이 연결할 수 있음 | |
// 단, n번째부터 N번째까지의 전깃줄 사이의 최댓값을 의미함.(0번째부터 N번째까지 연결 가능한 최대 전깃줄 수의 값이 아님) | |
// ex) dp[3] = 2; 3번째 전깃줄을 연결했을 때 4번째부터 N번째 전깃줄까지 교차하지 않는 전깃줄이 2개(3번째 포함) | |
static int find(int N) { | |
if (dp[N] == 0) { | |
dp[N] = 1; // 자기 자신 하나 연결(기본) | |
// N + 1번째 부터 N번째 전깃줄까지 연결 가능한 최대 전깃줄 수 구하기 | |
for (int i = N + 1; i < dp.length; i++) | |
if (wire[N][1] < wire[i][1]) // 현재 전깃줄과 i번째 전깃줄이 조건 2를 만족하면, | |
// 현재 값과 i번째 전깃줄을 연결했을 때의 연결 가능한 최대 전깃줄 값을 비교하여 더 큰 값 저장 | |
dp[N] = Math.max(dp[N], find(i) + 1); | |
} | |
return dp[N]; | |
} | |
public static void main(String[] args) throws IOException { | |
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); | |
// 전깃줄 개수 입력 | |
int N = Integer.parseInt(br.readLine()); | |
wire = new int[N][2]; // wire[N개의 전깃줄][0 = A전봇대, 1 = B전봇대] | |
dp = new int[N]; // dp[n] = m; n번째 전깃줄을 설치하면 최대 m만큼의 전깃줄을 교차없이 연결할 수 있음 | |
// N개의 전깃줄 입력(A-B) | |
StringTokenizer st; | |
for (int i = 0; i < N; i++) { | |
st = new StringTokenizer(br.readLine()); | |
wire[i][0] = Integer.parseInt(st.nextToken()); // A전봇대 | |
wire[i][1] = Integer.parseInt(st.nextToken()); // B전봇대 | |
} | |
// A전봇대 기준으로 오름차순 정렬 = 조건 1 만족 | |
Arrays.sort(wire, new Comparator<int[]>() { | |
@Override | |
public int compare(int[] o1, int[] o2) { | |
return o1[0] - o2[0]; | |
} | |
}); | |
// 연결 가능한 최대 전깃줄 갯수 찾기 | |
int max = 0; | |
for (int i = 0; i < N; i++) | |
if (max < find(i)) max = dp[i]; | |
// 출력 | |
// 없애야하는 전깃줄의 최소 개수 = 전체 전깃줄 갯수 - 연결 가능한 최대 전깃줄 갯수 | |
System.out.println(N - max); | |
} | |
} |

우악 어려운 문젠줄 알았는데 풀고보니...
왜 이렇게 시간을 들였나... 싶은
이차배열의 오름차순 정렬 알아간 문제였다.
'코딩 일기장 > 백준' 카테고리의 다른 글
[백준]동적 계획법1/연속합/1912 풀이 JAVA (0) | 2021.02.10 |
---|---|
[백준]동적 계획법1/LCS/9251 풀이 JAVA (0) | 2021.02.08 |
[백준]동적 계획법1/가장 긴 바이토닉 부분 수열/11054 풀이 JAVA (0) | 2021.02.01 |
[백준]동적 계획법1/가장 긴 증가하는 부분 수열/11053 풀이 JAVA (0) | 2021.01.31 |
[백준]동적 계획법1/포도주 시식/2156 풀이 JAVA (0) | 2021.01.27 |