[02565] 전깃줄

Byeongmin·2021년 10월 3일
0
post-thumbnail

[02565] 전깃줄

문제

두 전봇대 A와 B 사이에 하나 둘씩 전깃줄을 추가하다 보니 전깃줄이 서로 교차하는 경우가 발생하였다. 합선의 위험이 있어 이들 중 몇 개의 전깃줄을 없애 전깃줄이 교차하지 않도록 만들려고 한다.

예를 들어, < 그림 1 >과 같이 전깃줄이 연결되어 있는 경우 A의 1번 위치와 B의 8번 위치를 잇는 전깃줄, A의 3번 위치와 B의 9번 위치를 잇는 전깃줄, A의 4번 위치와 B의 1번 위치를 잇는 전깃줄을 없애면 남아있는 모든 전깃줄이 서로 교차하지 않게 된다.
< 그림 1 >
그림1

전깃줄이 전봇대에 연결되는 위치는 전봇대 위에서부터 차례대로 번호가 매겨진다. 전깃줄의 개수와 전깃줄들이 두 전봇대에 연결되는 위치의 번호가 주어질 때, 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 두 전봇대 사이의 전깃줄의 개수가 주어진다. 전깃줄의 개수는 100 이하의 자연수이다. 둘째 줄부터 한 줄에 하나씩 전깃줄이 A전봇대와 연결되는 위치의 번호와 B전봇대와 연결되는 위치의 번호가 차례로 주어진다. 위치의 번호는 500 이하의 자연수이고, 같은 위치에 두 개 이상의 전깃줄이 연결될 수 없다.

출력

첫째 줄에 남아있는 모든 전깃줄이 서로 교차하지 않게 하기 위해 없애야 하는 전깃줄의 최소 개수를 출력한다

코드

#include <iostream>

using namespace std;

/* 조건 */
#define MAX_LINE 101
#define MAX_POS 501 // max position. 전봇대의 위치의 최대 갯수

/* 변수 */
int N, arr[MAX_POS]; // 입력
int dp[MAX_POS]; // 각 arr[i]에 대한 LIS의 길이
int max_LIS = 0; // LIS값

/* 함수 */

int main() {
    /* 입력 */
    cin >> N;
    int tmp;
    for(int i = 0; i < N; i++) {
        cin >> tmp;
        cin >> arr[tmp];
        dp[i] = 1; // dp를 1로 초기화
    }

    /* 풀이 */
    for(int i = 0; i < MAX_POS; i++) {
        if(arr[i] == 0) { // A[i]에 전선이 없는 경우
            dp[i] = 0;
            continue;
        }
        for(int j = 0; j < i; j++) { // dp[i]에 LIS 업데이트
            if(arr[j] < arr[i] && dp[j] >= dp[i]) {
                dp[i] = dp[j] + 1;
                if(max_LIS < dp[i]) // max_LIS 업데이트
                    max_LIS = dp[i];
            }
        }
    }

    /* 출력 */
    cout << N - max_LIS << '\n';
}

풀이

개념

  • A전봇대 기준으로 숫자가 증가하는 방향으로 가면서 B에 연결된 전깃줄의 번호가 줄어들지 않을 때 전깃줄이 교차하지 않는다.
  • 위의 경우는 배열 arr[i]의 값을 A전봇대의 i위치와 연결된 B전봇대의 위치라고 했을 때, arr의 LIS(Longest Increasing Subsequence)만 남기고 나머지를 제거하면 된다.
  • [11053] 가장 긴 증가하는 부분 수열
    • LIS를 구하는 과정은 위와 같다.
    • 단, 중간에 전선이 없는 부분을 고려해야 한다.

코드설명

  • 변수
    • N 전깃줄의 개수
    • arr[] 각 arr[i]에 대하여 arr[i]는 A의 i에 연결된 전깃줄이 B의 몇번 위치에 연결되었는지 나타낸다.
    • dp[] 각 arr[i]에 대한 LIS의 길이
    • max_LIS 모든 dp[i]의 최댓값 (LIS)
  • 입력
    • 먼저 N을 입력받는다.
    • 다음을 N회 반복한다.
      • tmp에 임시로 입력을 받는다.
      • arr[tmp]에 해당 위치와 B와 연결된 위치를 입력한다.
    • 위의 반복문으로 각 arr[i]에는 A전봇대에서 i위치와 연결된 B전봇대의 위치가 저장되어 있다.
  • 풀이
    • 다음을 전봇대의 최대 위치의 수만큼 반복한다.
      • 만약 arr[i]가 0라면 (i위치에 연결된 전선이 없다면) dp[i] = 0으로 하고, i+1로 건너뛴다.
      • 만약 i보다 앞의 숫자들인 arr[j]중 arr[i]보다 작은 숫자가 있고, 해당 dp[j]가 현재 dp[i]보다 크거나 같을 경우 dp[i] = dp[i] + 1
        • 위의 원리는 [11053] 가장 긴 증가하는 부분 수열의 풀이를 참고하면 된다.
      • 구한 값이 max_LIS보다 클 경우 max_LIS 업데이트
  • 출력
    • 구한 LIS는 남길 수 있는 최대 전깃줄의 갯수이므로, 모든 전깃줄의 수에서 구한 값을 빼면 제거해야 하는 최소한의 전깃줄의 수가 나온다.

출처

백준
[02565] 전깃줄
https://www.acmicpc.net/problem/2565

profile
Handong Global Univ.

0개의 댓글