본문 바로가기
Algorithm/Basic

[알고리즘-기초] 완전 탐색, 브루트 포스(Brute Force)

by s_y_130 2022. 12. 16.

완전 탐색, 브루트 포스란?

Brute Force의 사전적 의미를 보면 다음과 같다.

 

brute: 무식한 +  force: 힘   

 

무식한 힘으로 해석할 수 있다.

 

즉, 가능한 모든 경우의 수를 모두 탐색하면서 요구조건에 충족되는 결과만을 가져온다.

이 알고리즘의 강력한 점은 예외 없이 100%의 확률로 정답만을 출력한다.

 

 

장점

  • 알고리즘을 설계하고 구현하기 쉽다.
  • 복잡한 알고리즘 없이 빠르게 구현할 수 있다.

 

 

 

단점

  • 알고리즘 실행 시간이 매우 오래 걸린다.
  • 메모리 효율 쪽으로 매우 비효율적이다.

 

 

종류

 

브루트 포스는 기본 구조는 크게 선형 구조와 비선형 구조로 나눌 수 있다.

 

  • 선형 구조 : 순차 탐색
  • 비선형 구조 : 깊이 우선 탐색(DFS), 너비 우선 탐색(BFS)
    • 심화 : 백트래킹(재귀)

백트래킹과 DFS, BFS에 대해서는 나중에 그래프 탐색 알고리즘과 관련이 있으므로 여기서는 순차 탐색만 파악해보도록 하겠다.

 

 

컴퓨터는 약 1초에 1억번(10^8)의 연산이 가능하다고 알려져있는데,

브루트포스는 전체 탐색하기 때문에 좋은 알고리즘 방식이 아니다.

(600억을 확인한다면... 600초 = 확인하는데만 10분...)

 

그래서 실제 알고리즘을 풀땐, 이 문제가 브루트포스로 가능한지 확인 후

불가능하다면 어떤 알고리즘을 적용해서 시간복잡도를 줄일지 확인해야한다.(DP,누적합,이분탐색 등등)

 

 

예시

 

예를 들어, 4자리 숫자로 된 핸드폰의 암호는 0000, 0001, 0002... 9999 까지 총 1만개(104)의 조합 중 하나이므로, 이를 하나씩 대입해 보면 핸드폰의 암호를 통과할 수 있게 된다. 한 번 암호를 입력해 보는데 5초가 걸린다면, 5만 초, 즉 14시간이면 충분하고, 이를 사람 손이 아닌 컴퓨터로 처리할 수 있다면 1초 이내로 찾아낼 수 있게 되는 것이다.

 

하지만 브루트 포스는 자원이 문제, 복잡도에 매우 민감하다는 치명적인 단점을 가지고 있다. (세상의 모든 문제가 브루트 포스로 풀 수 있었으면 효율 좋은 알고리즘 도구도 안 나왔을 것...)

위에서 예시로 들었던 4자리 숫자 핸드폰 암호를 알아보는 시간 복잡도만 해도 코드로 짜게 되면

O(n^4)

이 되게 된다. 매우 비효율 적이다. 만약에 자리가 숫자가 아니라 문자였다면 자원의 할당도 엄청 나게 늘어날 것이다.

하지만 브루트 포스 방식으로 써야하는 순간에는 브루트 포스 방식으로 풀어야한다.


 

문제 해결 방법

  1. 주어진 문제를 선형 구조로 구조화 한다.
  2. 구조화된 문제공간을 적절한 방법으로 해를 구성할 때까지 탐색한다.
  3. 구성된 해를 정리한다.

선형 구조로 구조화 한다는 이야기가 어렵게 들리겠지만, 문제에서 주어진 상황을 컴퓨터가 풀기 쉽게 정리하면 되는 것이다.

 

 

예제 및 알고리즘

1. 10의 약수의 합을 구하기

10의 약수가 될 수 있는 모든 자연수를 구조화 하자.

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} → 문제의 해가 될 수 있는 자료를 선형으로 구성하였다.

 

구조화된 자료가 선형 구조이므로 순차 탐색을 활용하여 첫 번째 원소부터 마지막 원소까지 탐색한다.

탐색하면서 10의 약수가 되는 값만 남겨두고 10의 약수가 될 수 없는 값을 배제한다.

10의 약수는 10을 현재 원소로 나누어떨어지면 그 원소는 10의 약수이다.

위의 과정을 거치면 집합은 다음과 같이 정리된다.

{1, 2, 5, 10}

 

마지막으로 탐색결과를 정리하여 최종 해를 구한다.

1 + 2 + 5 + 10 = 18

 

위 문제를 표현해보자.

 

1
2
3
4
5
6
7
int sum = 0;
for(int i = 1; i <= n; i = i + 1) }
    if(n % i == 0) {
        sum = sum + i;
    }
}
 
cs

 

 

2. 거스름돈을 지불할 수 있는 방법의 수와 최소 동전의 개수 구하기

10원과 50원으로 120원을 지불할 수 있는 모든 방법의 수와 최소 동전의 개수를 구해보자.

 

주어진 동전의 종류가 2가지이므로 2차원 즉 행렬의 형태로 구조화하여 일반적 방법으로 해결할 수 있다.

행을 50원, 열을 10원으로 생각하고 구조화해보자.

행렬

위 행렬에서 행렬(0, 0)은 50원 동전 0개, 10원 동전은 0개를 지불하는 방법으로 생각할 수 있다.

따라서 행렬(1, 7)은 50원 동전 1개, 10원 동전 7개로 120원을 지불하는 방법이 된다.

 

구조화하고 행렬을 2차원으로 탐색하여 120을 이루는 모든 경우의 수를 조사하여, 구한 값들 중 행의 값 + 열의 값의 합의 최소값을 찾으면 최소 동전의 수가 된다.

 

위 행렬을 탐색해 보면 120원을 지불할 수 있는 경우의 수는 (0, 12), (1, 7), (2, 2)의 3가지이며, 이들의 사용한 동전의 수는 각 행과 열의 합이다. 따라서 사용한 최소 동전의 수는 이 값들 중 최소값이므로 4이다.

 

120원을 지불할 수 있는 모든 경우의 수 : 3가지, 최소 지불 동전의 수 : 4개

 

위 문제를 표현해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
int change = 120;
int ways = 0
int min = INF;
 
for(i = 0; i * 50 <= change; i = i + 1) {
  for(j = 0; j * 10 <= change; j = j + 1) {
     if( (i * 50+ (j * 10= change) {
        ways = ways + 1;
        if(min > i+j)
           min = i+j;
     }
  }
}
 
cs

 

 

 

 

관련 문제

 

[일곱 난쟁이]

[블랙잭]

[셀프넘버]

[한수]

 


참고

 

https://hcr3066.tistory.com/26

https://go-coding.tistory.com/67

https://foreverhappiness.tistory.com/104

https://nahwasa.com/entry/%EB%B8%8C%EB%A3%A8%ED%8A%B8%ED%8F%AC%EC%8A%A4-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Brute-force-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

https://cano721.tistory.com/64