Computer Science
탄탄한 기반 실력을 위한
전공과 이론 지식 모음
Today I Learned!
배웠으면 기록을 해야지
TIL 사진
Flutter 사진
Flutter로 모바일까지
거꾸로캠퍼스 코딩랩 Flutter 앱개발 강사
스파르타코딩클럽 즉문즉답 튜터
카카오테크캠퍼스 3기 학습코치
프로필 사진
박성민
임베디드 세계에
발을 들인 박치기 공룡
임베디드 사진
EMBEDDED SYSTEM
임베디드 SW와 HW, 이론부터 실전까지
ALGORITHM
알고리즘 해결 전략 기록
🎓
중앙대학교 소프트웨어학부
텔레칩스 차량용 임베디드 스쿨 3기
애플 개발자 아카데미 1기
깃허브 사진
GitHub
프로젝트 모아보기
Instagram
인스타그램 사진

Develop/알고리즘

[백준] 2352 - 반도체 설계

sm_amoled 2021. 8. 9. 12:53

문제 링크

https://www.acmicpc.net/problem/2352

문제

반도체를 설계할 때 n개의 포트를 다른 n개의 포트와 연결해야 할 때가 있다.

예를 들어 왼쪽 그림이 n개의 포트와 다른 n개의 포트를 어떻게 연결해야 하는지를 나타낸다. 하지만 이와 같이 연결을 할 경우에는 연결선이 서로 꼬이기 때문에 이와 같이 연결할 수 없다. n개의 포트가 다른 n개의 포트와 어떻게 연결되어야 하는지가 주어졌을 때, 연결선이 서로 꼬이지(겹치지, 교차하지) 않도록 하면서 최대 몇 개까지 연결할 수 있는지를 알아내는 프로그램을 작성하시오

입력

첫째 줄에 정수 n(1 ≤ n ≤ 40,000)이 주어진다. 다음 줄에는 차례로 1번 포트와 연결되어야 하는 포트 번호, 2번 포트와 연결되어야 하는 포트 번호, …, n번 포트와 연결되어야 하는 포트 번호가 주어진다. 이 수들은 1 이상 n 이하이며 서로 같은 수는 없다고 가정하자.

출력

첫째 줄에 최대 연결 개수를 출력한다.

조건

  • 시간 제한 : 2s
  • 메모리 제한 : 128MB

해설

문제를 잘 읽어보면 꼬이지 않게 포트를 선택하기 위해서는 선택한 포트의 번호가 계속 증가해야 한다. 이전에 선택한 포트 번호보다 작으면 줄이 꼬이기 때문이다. 이 점을 본다면 나열된 숫자 배열에서 선택한 원소들이 오름차순으로 정렬된 배열을 만드는 알고리즘이므로, LDS(가장 긴 증가하는 부분 수열) 알고리즘을 이용해 풀 수 있다는 것을 알 수 있다.

풀이

Input을 받아와 동적으로 메모리 공간을 생성하기 위해 vector를 사용해주었다. lds 벡터는 lds 알고리즘을 해결하기 위해 사용되는 벡터이다.

int N;
cin >> N;

vector<int> arr(N);
vector<int> lds;
for(int i = 0; i < N; i++) {
    cin >> arr[i];
}

우선 lds.back()이 메모리 참조에서 오류가 발생하지 않도록 하기 위해 첫번째 원소를 lds에 넣어주고 시작한다. lds 벡터의 최댓값보다 비교하는 원소가 크다면 push_back() 함수를 통해 넣어주고, 작다면 lds 벡터에서 해당 원소보다 큰 가장 작은 값을 찾아 자리를 대체한다. (작은 값일수록 더 긴 배열을 만들기에 유리하기 때문에) 이 알고리즘에 대해 더 자세하게 알고싶다면 LDS 알고리즘을 찾아보자. 마지막에 lds 벡터의 사이즈가 만들 수 있는 부분 수열의 최대길이이자, 선택할 수 있는 포트의 최대 개수이다.

// initial value
lds.push_back(arr[0]);

for(int i = 1; i < N; i++) {
    if(lds.back() < arr[i]) {
        lds.push_back(arr[i]);
    } else {
        int left = 0, right = lds.size();
        int mid;
        while(left <= right) {
            mid = (left+right)/2;
        
            if(lds[mid] <= arr[i]) {
                left=mid+1;
            } else {
                right=mid-1;
            }
        }
        lds[left] = arr[i];
    }
}

printf("%d\n", (int)lds.size());


코멘트

수학 활용 문제를 만난 기분이다. 뭔가 숨겨져있어서, 파헤쳐봤더니 LDS 문제네 ㅎㅎ. 이정도 난이도의 숨겨진 알고리즘을 찾아내는 문제라면 기분좋게 풀어낼 수 있을 것 같다.


코드

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main() {
    int N;
    cin >> N;
    
    vector<int> arr(N);
    vector<int> lds;
    for(int i = 0; i < N; i++) {
        cin >> arr[i];
    }
    
    // initial value
    lds.push_back(arr[0]);
    for(int i = 1; i < N; i++) {
        if(lds.back() < arr[i]) {
            lds.push_back(arr[i]);
        } else {
            int left = 0, right = lds.size();
            int mid;
            while(left <= right) {
                mid = (left+right)/2;
            
                if(lds[mid] <= arr[i]) {
                    left=mid+1;
                } else {
                    right=mid-1;
                }
            }
            lds[left] = arr[i];
        }
    }
    
    printf("%d\n", (int)lds.size());
    return 0;
}
320x100