Post

BOJ_7570_줄 세우기 (Java, C++)

BOJ_7570_줄 세우기 (Java, C++)

[Gold II] 줄 세우기 - 7570

문제 링크

성능 요약

메모리: 5928 KB, 시간: 104 ms

분류

다이나믹 프로그래밍, 그리디 알고리즘

제출 일자

2025년 1월 29일 03:37:46

문제 설명

대한 어린이집에 올해 입학한 어린이들이 놀이터에 한 줄로 서있다. 모든 어린이들에게는 입학할 때 주어진 번호가 있고 모두 옷에 번호표를 달고 있다. 그런데 어린이들은 아직 번호 순서대로 줄을 잘 서지 못하므로 선생님이 다음과 같은 방법을 사용해서 번호순서대로 줄을 세우려고 한다.

방법: 줄 서있는 어린이 중 한 명을 선택하여 제일 앞이나 제일 뒤로 보낸다.

위의 방법을 사용할 때 어린이가 이동해서 빈자리가 생기는 경우에는 빈자리의 뒤에 있는 어린이들이 한 걸음씩 앞으로 걸어와서 빈자리를 메꾼다.

예를 들어, 5명의 어린이들에게 1부터 5까지의 번호가 주어져 있고, 다음과 같은 순서로 줄 서있다고 하자.

5 2 4 1 3

위 방법을 이용해서 다음과 같이 번호순서대로 줄을 세울 수 있다.

  1. 1번 어린이를 제일 앞으로 보낸다. (5 2 4 1 3 → 1 5 2 4 3)
  2. 4번 어린이를 제일 뒤로 보낸다. (1 5 2 4 3 → 1 5 2 3 4)
  3. 5번 어린이를 제일 뒤로 보낸다. (1 5 2 3 4 → 1 2 3 4 5)

위의 예에서는 세 명의 어린이를 제일 앞이나 제일 뒤로 보내 번호순서대로 줄을 세웠다. 그리고 두 명 이하의 어린이를 제일 앞이나 제일 뒤로 보내는 방법으로는 번호순서대로 줄을 세울 수 없다. 그러므로 이 경우에는 최소한 세 명의 어린이를 이동하여야 번호순서대로 줄을 세울 수 있다.

이 문제는 처음에 줄서있는 상태에서 위 방법을 이용해서 번호순서대로 줄을 세울 때 앞이나 뒤로 보내는 어린이 수의 최솟값을 찾는 것이다.

입력

입력은 2 개의 줄로 이루어져 있다. 첫 줄에는 어린이 수를 나타내는 정수가 주어진다. 둘째 줄에는 처음에 줄서있는 어린이들의 번호가 차례대로 주어진다. 주어진 번호들 사이에는 공백이 하나씩 들어있다. 단, 어린이 수는 1이상 1,000,000이하의 정수로 제한되고, 어린이 수가 N이면 어린이들의 번호는 1부터 N까지의 정수이다.

출력

입력에서 주어진 어린이들의 줄에 대해 번호순서대로 줄을 세우기 위해 제일 앞이나 제일 뒤로 보내는 어린이 수의 최솟값을 출력해야 한다.

문제 풀이

아이디어는 LIS알고리즘이다. LIS알고리즘을 사용하면서 1씩 증가하는 최장 수열을 찾으면 나머지 숫자을 앞뒤에 최적으로 붙일 수 있기 때문에다. O ( $N^2$ ) 이 원래의 LIS지만 시간초과가 발생했다. 그래서 이 문제의 경우엔 특별히 O(N)으로 1씩 증가하는 LIS를 구하도록 dp를 설계했다.

dp[i] = dp[i-1] + 1, 기본 0으로 초기화. dp[i] = i로 끝나는 1씩 증가하는 최장 증가하는 수열 (연속하지 않아도 됨)

코드

Java 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * Author: nowalex322, Kim HyeonJae
 */

import java.io.*;
import java.util.*;

public class Main {
    static BufferedReader br;
    static BufferedWriter bw;
    static StringTokenizer st;
    static int N, dp[], maxLISLen=1;
    public static void main(String[] args) throws Exception {
        new Main().solution();
    }

    public void solution() throws Exception {
        br = new BufferedReader(new InputStreamReader(System.in));
//        br = new BufferedReader(new InputStreamReader(new FileInputStream("src/main/java/BOJ_7570_줄세우기/input.txt")));
        bw = new BufferedWriter(new OutputStreamWriter(System.out));

        N = Integer.parseInt(br.readLine());
        dp = new int[N + 1]; // dp[i] = i로 끝나는 LIS길이
        Arrays.fill(dp, 0);
        st = new StringTokenizer(br.readLine());

        for(int i=1; i <= N; i++){
            int n = Integer.parseInt(st.nextToken());
            dp[n] = dp[n-1] + 1;
            maxLISLen = Math.max(maxLISLen, dp[n]);
        }
        bw.write(String.valueOf(N - maxLISLen));
        bw.flush();
        bw.close();
        br.close();
    }
}

C++ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * Author: nowalex322, Kim HyeonJae
 */
#include <bits/stdc++.h>
using namespace std;

// #define int long long
#define MOD 1000000007
#define INF LLONG_MAX
#define ALL(v) v.begin(), v.end()

#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif

int N, maxLISLen = 1;
vector<int> dp;

void solve() {
    cin >> N;
    dp.resize(N + 1, 0);
    for (int i = 1; i <= N; i++) {
        int n;
        cin >> n;
        dp[n] = dp[n - 1] + 1;
        maxLISLen = max(maxLISLen, dp[n]);
    }
    cout << N - maxLISLen << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tt = 1;  // 기본적으로 1번의 테스트 케이스를 처리
    // cin >> tt;    // 테스트 케이스 수 입력 (필요 시)

    while (tt--) {
        solve();
    }
    return 0;
}
This post is licensed under CC BY 4.0 by the author.