문제:

정수 N이 주어졌을 때, 소인수분해하는 프로그램을 작성하시오.

 

입력:

첫째 줄에 정수 N (1 ≤ N ≤ 10,000,000)이 주어진다.

 

출력:

N의 소인수분해 결과를 한 줄에 하나씩 오름차순으로 출력한다. N이 1인 경우 아무것도 출력하지 않는다.


풀이:

소인수분해 문제를 해결하기 위해서는 우선 소수를 판정하는 방법에 대해 알아야한다.

어떤 수 $x$가 소수일 조건은 약수로 1과 자기 자신만을 가져야 한다. 따라서 $x$를 $[2, x - 1]$ 범위 내의 수로 나누었을때, 나누어 떨어지는 수가 없으면 그 수는 소수이다. 이를 코드로 표현하면 다음과 같다.

bool IsPrime(int x) {
    for (int i = 2; i < x; ++i) {
        if (x % i == 0)
            return false;
    }
    return true;
}

 

위 알고리즘의 시간복잡도는 $O(x)$이다. 이 시간복잡도를 줄일 수가 있는데 이론은 다음과 같다.

 


$\sqrt{x}$ 보다 큰 수 $d$가 $x$의 약수라고 하자. ($\sqrt{x} < d$)
그럼, $x = d * m$이 성립하는 $m$이 존재한다. $d$와 $m$의 곱은 $x$보다 작아야 하므로 ($m < \sqrt{x} < d$)라는 부등식을 세울 수 있다.
즉, $\sqrt{x}$보다 작은 수 $y$가 $x$의 약수이면 $y$와 곱했을때, $x$가 나오는 수가 반드시 존재하는 것이다.
따라서, 우리는 다음과 같이 소수 판정의 범위를 줄일 수가 있다.

 

bool IsPrime(int x) {
    for (int i = 2; i*i <= x; ++i) {
        if (x % i == 0)
            return false;
    }
    return true;
}

이를 통해 우린 시간복잡도를 $O(\sqrt{x})$로 줄일 수 있다.

 

소수를 판정하는 대표적인 방법으로는 에라토스테네스의 체가 있다. 에라토스테네스의 체는 1과 자기자신 사이에 약수의 배수를 모두 지우면 남는 수가 약수라는 이론이다.

https://ko.wikipedia.org/wiki/%EC%97%90%EB%9D%BC%ED%86%A0%EC%8A%A4%ED%85%8C%EB%84%A4%EC%8A%A4%EC%9D%98_%EC%B2%B4

 

에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전

수학에서 에라토스테네스의 체는 소수를 찾는 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 알고리즘[편집] 2부터 소수를 구하고자 하는 구간의 모든 수를 나열한다. 그림에서

ko.wikipedia.org

 

이제 이를 활용해 문제를 풀어보도록 하자.

예를 들어, $72$가 있으면 $2*2*2*3*3$으로 표현된다. 이를 살펴보면 2로 가능한 나누어 표현하고 그 다음으로 3으로 가능한 나누어 표현하였다.

따라서 우리는 어떤 수 $x$에 대해 작은 수부터 가능할 때까지 나누어주며 그 수를 출력해주면 된다. 범위는 앞선 알고리즘에서 살펴본 바로 $[2, \sqrt{x} - 1]$ 까지로 하면 된다. 결과적으로 2의 배수, 3의 배수, 5의 배수...가 차례대로 지워지면서 소인수들이 갯수만큼 출력이 된다.

 

#include <iostream>
using namespace std;

void __init() {
  cin.tie(0);
  ios::sync_with_stdio(0);
}

void Factorization(int num) {
  for(int i = 2; i*i <= num; i++) {
    while(num % i == 0) {
      cout << i << "\n";
      num /= i;
    }
  }
  if(num != 1) cout << num;
}

int main() {
  int num;

  __init();

  cin >> num;
  Factorization(num);
}
반응형

'알고리즘 > 백준' 카테고리의 다른 글

[Baekjoon] 백준 11048: 이동  (0) 2021.05.19

문제:

준규는 N×M 크기의 미로에 갇혀있다. 미로는 1×1크기의 방으로 나누어져 있고, 각 방에는 사탕이 놓여져 있다. 미로의 가장 왼쪽 윗 방은 (1, 1)이고, 가장 오른쪽 아랫 방은 (N, M)이다.

준규는 현재 (1, 1)에 있고, (N, M)으로 이동하려고 한다. 준규가 (r, c)에 있으면, (r+1, c), (r, c+1), (r+1, c+1)로 이동할 수 있고, 각 방을 방문할 때마다 방에 놓여져있는 사탕을 모두 가져갈 수 있다. 또, 미로 밖으로 나갈 수는 없다.

준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수의 최댓값을 구하시오.

 

입력:

첫째 줄에 미로의 크기 N, M이 주어진다. (1 ≤ N, M ≤ 1,000)

둘째 줄부터 N개 줄에는 총 M개의 숫자가 주어지며, r번째 줄의 c번째 수는 (r, c)에 놓여져 있는 사탕의 개수이다. 사탕의 개수는 0보다 크거나 같고, 100보다 작거나 같다.

 

출력:

첫째 줄에 준규가 (N, M)으로 이동할 때, 가져올 수 있는 사탕 개수를 출력한다.


풀이:

오른쪽, 아래, 대각선으로 이동가능하지만 대각선은 배제하고 생각해도 된다. 그 이유는 우선, 대각선으로 이동하기 위해서는 대각선 or 아래 -> 오른쪽 or 오른쪽 -> 아래 세 가지 길이 있다. 최대한 많은 사탕을 먹어야 하므로 지름길인 대각선 방향은 배제한다.

y와 x의 범위 체크를 위해 isValidCoord 함수를 사용했고, 아래, 오른쪽으로 이동을 표현하기 위해 구조체 dir을 만들었다.

 

문제를 처음 보고 나는 DFS를 떠올렸다. 그래서 DFS로 짜기 시작했는데 코드를 진행하다 보니 사탕의 양을 저장해 줄 DP가 필요하다는 것을 깨달았다. DFS와 DP를 이용해서 풀어야지 마음 먹고 다시 짜 내려갔는데 이 문제는 DFS를 쓰면 오히려 더욱 복잡해지는 문제라는 것을 알았다. 단순 완전탐색으로 DP를 활용해 진행하면 된다.

 

코드:

#include <iostream>
#include <algorithm>
#define DIR 2
using namespace std;

int N, M;
int Maze[1001][1001];
int DP[1001][1001];

typedef struct {
    int y, x;
} Dir;

Dir dir[DIR] = {{0,1},{1,0}};

bool isValidCoord(int y, int x) {
    return 0 <= y && y < N && 0 <= x && x < M;
}

int main() {
    cin >> N >> M;
    for (int i = 0; i < N; ++i)
        for (int j = 0; j < M; ++j)
            cin >> Maze[i][j];

    DP[0][0] = Maze[0][0];

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            for (int k = 0; k < DIR; ++k) {
                int dy = i + dir[k].y;
                int dx = j + dir[k].x;

                if(isValidCoord(dy, dx))
                    DP[dy][dx] = max(DP[dy][dx], DP[i][j] + Maze[dy][dx]);
            }
        }
    }

    cout << DP[N-1][M-1];
}

 

GIT:

https://github.com/tmsksfh2012/Algorithm/blob/main/%EB%B0%B1%EC%A4%80%2011048/main.cpp

 

tmsksfh2012/Algorithm

백준 알고리즘 공부. Contribute to tmsksfh2012/Algorithm development by creating an account on GitHub.

github.com

반응형

'알고리즘 > 백준' 카테고리의 다른 글

[BaekJoon] 백준 11653: 소인수분해  (0) 2021.11.07

wooder2050.medium.com/%EB%8F%99%EC%A0%81%EA%B3%84%ED%9A%8D%EB%B2%95-dynamic-programming-%EC%A0%95%EB%A6%AC-58e1dbcb80a0

 

동적계획법(Dynamic Programming) 정리

동적계획법은 문제의 최적해를 구하거나 답의 개수를 세는 과정에 사용할 수 있는 알고리즘 설계 기법입니다. 동적계획법을 사용하면 불필요한 계산을 줄이고, 효율적으로 최적해를 찾을 수 있

wooder2050.medium.com

 

반응형

+ Recent posts