안녕하세요! 코딩하는 경제학도 쏘코입니다.

오늘 풀어본 문제는 완전탐색의 마지막 문제인 카펫입니다.

 

출처 : 프로그래머스 코딩테스트 연습 고득점KIT, programmers.co.kr/learn/courses/30/lessons/42842

 

코딩테스트 연습 - 카펫

Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다. Leo는 집으로 돌아와서 아까 본 카펫의 노란색과

programmers.co.kr

목차


    0. 문제 설명

    Leo는 카펫을 사러 갔다가 아래 그림과 같이 중앙에는 노란색으로 칠해져 있고 테두리 1줄은 갈색으로 칠해져 있는 격자 모양 카펫을 봤습니다.

    Leo는 집으로 돌아와서 아까 본 카펫의 노란색과 갈색으로 색칠된 격자의 개수는 기억했지만, 전체 카펫의 크기는 기억하지 못했습니다.

    Leo가 본 카펫에서 갈색 격자의 수 brown, 노란색 격자의 수 yellow가 매개변수로 주어질 때 카펫의 가로, 세로 크기를 순서대로 배열에 담아 return 하도록 solution 함수를 작성해주세요.

     

    0.0. 제한사항

    • 갈색 격자의 수 brown은 8 이상 5,000 이하인 자연수입니다.
    • 노란색 격자의 수 yellow는 1 이상 2,000,000 이하인 자연수입니다.
    • 카펫의 가로 길이는 세로 길이와 같거나, 세로 길이보다 깁니다.

    0.1. 입출력 예

    brown yellow return
    10 2 [4, 3]
    8 1 [3, 3]
    24 24 [8, 6]

    1. 풀이 과정

    풀고 나서 왜이렇게 복잡하게 생각했지 하는 생각이 들었습니다...

    기본적으로 알아야 할 것은 return값에 들어갈 두 값의 합은 brown과 yellow의 합이라는 것과 yellow타일은 brown타일로 둘러싸였기 때문에 return값에서 각각 -2씩을 해준 값들을 곱하면 yellow만 나와야 한다는 것입니다. 

     

    그래서 저는 두 가지의 순서로 진행했는데,

    첫 번째는 brown과 yellow를 더한 total의 약수를 담은 vector를 만들고

    두 번째는 곱했을 때 total이 되는 약수들에 -2씩 해서 곱한 것이 yellow가 나오는 지 확인했습니다.

     

    먼저 약수를 구하기 위해서 total을 나눠줍니다. 이전 문제와 동일하게 total의 제곱근까지만 나눠주면 절반은 해결됩니다.

    이제 나머지 절반을 구하기 위해서 total에서 앞에서 구한 약수를 나눠줍니다. 그 값들을 넣어줍니다. 저는 순서를 맞춰주기 위해서 for문을 거꾸로 돌렸는데, 그냥 넣고 sort해도 됩니다.

     

    이제 곱했을 때 total이 되는 약수짝들에 -2씩 해서 곱한 것이 yellow가 되는지 확인합니다. 이 조건이 붙는 이유는 처음에 설명했으므로 넘어가도록 하겠습니다.

    약수들을 구할 때 total의 제곱근을 2번 넣어준 이유가 여기서 대칭으로 곱했기 때문입니다. total의 제곱근 * total의 제곱근 = total이라는 상황을 만들어주기 위해서이죠.

     

    yellow가 나오면, answer에 두 값을 넣어줍니다. 큰 수를 먼저 넣고(가로) 작은 수(세로)를 넣어줍니다. 이건 제한사항에 나와있는 내용이기 때문에 순서를 바꾸면 안됩니다!


    2. 소스 코드

    #include <string>
    #include <vector>
    #include <cmath>
    
    using namespace std;
    
    vector<int> solution(int brown, int yellow) {
        vector<int> answer;
        vector<int> divisor;
        divisor.push_back(1); // 1은 모든 수의 약수니까
        int total = brown + yellow;
        
        // 1. 약수 구하기 (total의 제곱근은 2번 들어가야함!)
        for(int i = 2; i <= sqrt(total); ++i){
            if(total % i == 0){
                divisor.push_back(i);
            }
        }
        
        for(int i = divisor.size()-1; i >= 0; --i)
            divisor.push_back(total/(divisor[i]));
        
        // 2. 곱했을 때 total이 되는 약수들에 -2씩 해서 곱한 것이 yellow가 나오는지 확인
        for(int i = 1; i < divisor.size()/2; ++i){ // 어짜피 1은 아닐테니 1부터 시작
            if ((divisor[i]-2) * (divisor[divisor.size()-1-i]-2) == yellow){
                answer.push_back(divisor[divisor.size()-i-1]);
                answer.push_back(divisor[i]);
                break;
            }
        }
        return answer;
    }


    3. 후기

    재미있는 문제였습니다. 엄청 어려워 보이면서도, 이전 문제를 풀었다면 수월하게 접근할 수 있는 문제이기도 했습니다. 문제를 꼼꼼히 읽고 어째서 이런 return값이 나왔는지만 확인하면 그 다음부터는 쉬운 문제였습니다. 하지만 저처럼 굳이 for문 안에서 복잡하게 하지 마시고 (divisor[divisor.size()-i-1 처럼...) algorithm 헤더의 sort를 이용한다면 보다 보기 좋게 만들 수도 있어 보입니다! 

    반응형
    • 네이버 블로그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기