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

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

 

출처 : 프로그래머스 코딩테스트 연습 고득점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를 이용한다면 보다 보기 좋게 만들 수도 있어 보입니다! 

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