※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 3188번 문제인 nule이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/3188
3188번: nule
We are given a game board consisting of squares arranged in N rows and N columns, with each square containing a single non-negative integer In the beginning of the game, a piece is situated on the top-left square (1,1) and it has to get to the bottom-right
www.acmicpc.net
좌상단의 칸에서 우하단의 칸으로 우측 방향과 아래 방향으로의 인접한, 0이 아닌 칸으로의 이동만을 이용한 경로 중 그 경로상의 칸에 적힌 모든 정수의 곱을 10진수로 나타냈을 때의 trailing zero의 최소 개수를 묻는 문제이다. (좌상단에서 우하단으로 이동이 가능한 입력만 주어짐을 문제가 보장한다.)
어떤 경로 T가 trailing zero가 최소가 되게 하는 경로 중 하나라고 해보자. 그리고 이 때 T 위의 모든 칸의 정수를 곱한 수가 소인수로 2를 p개, 5를 q개 가지고 있다고 해보자. 여기서 p<=q라면 모든 경로에 대하여 모든 칸의 정수를 곱한 수가 가지는 소인수 2의 개수가 p 이하여야 하고 마찬가지로 p>=q라면 모든 경로에 대하여 모든 칸의 정수를 곱한 수가 가지는 소인수 5의 개수가 q 이하여야 함을 관찰하자.
위의 관찰에 따라, 문제의 답은 좌상단 칸에서 우하단 칸으로 이동하는 경로 중 모든 칸의 정수를 곱한 수가 가지는 (소인수 2의 개수가 최소인 경로의 2의 개수)와 (소인수 5의 개수가 최소인 경로의 5의 개수) 두 값중 더 작은 값임을 알 수 있다.
이는 dp를 이용해 \(O(N^2)\)에 계산할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
using namespace std;
int N;
int arr[1000][1000];
int dp[1000][1000][2];
int cnt2, cnt5;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for (int r = 0; r < N; r++) {
for (int c = 0; c < N; c++) {
cin >> arr[r][c];
}
}
while (arr[0][0] % 2 == 0) arr[0][0] /= 2, cnt2++;
while (arr[0][0] % 5 == 0) arr[0][0] /= 5, cnt5++;
dp[0][0][0] = cnt2, dp[0][0][1] = cnt5;
for (int c = 1; c < N; c++) {
int& arr0c = arr[0][c];
if (arr0c == 0) dp[0][c][0] = dp[0][c][1] = 1000000007;
else {
cnt2 = cnt5 = 0;
while (arr0c % 2 == 0) arr0c /= 2, cnt2++;
while (arr0c % 5 == 0) arr0c /= 5, cnt5++;
dp[0][c][0] = min(dp[0][c - 1][0] + cnt2, 1000000007), dp[0][c][1] = min(dp[0][c - 1][1] + cnt5, 1000000007);
}
}
for (int r = 1; r < N; r++) {
int& arrr0 = arr[r][0];
if (arrr0 == 0) dp[r][0][0] = dp[r][0][1] = 1000000007;
else {
cnt2 = cnt5 = 0;
while (arrr0 % 2 == 0) arrr0 /= 2, cnt2++;
while (arrr0 % 5 == 0) arrr0 /= 5, cnt5++;
dp[r][0][0] = min(dp[r - 1][0][0] + cnt2, 1000000007), dp[r][0][1] = min(dp[r - 1][0][1] + cnt5, 1000000007);
}
}
for (int r = 1; r < N; r++) {
for (int c = 1; c < N; c++) {
int& arrrc = arr[r][c];
if (arrrc == 0) dp[r][c][0] = dp[r][c][1] = 1000000007;
else {
cnt2 = cnt5 = 0;
while (arrrc % 2 == 0) arrrc /= 2, cnt2++;
while (arrrc % 5 == 0) arrrc /= 5, cnt5++;
dp[r][c][0] = min(dp[r - 1][c][0], dp[r][c - 1][0]) + cnt2, dp[r][c][1] = min(dp[r - 1][c][1], dp[r][c - 1][1]) + cnt5;
}
}
}
cout << min(dp[N - 1][N - 1][0], dp[N - 1][N - 1][1]);
}
'BOJ' 카테고리의 다른 글
[BOJ 18266 // C++] Meetings (0) | 2023.10.10 |
---|---|
[BOJ 18267 // C++] Milk Visits (0) | 2023.10.09 |
[BOJ 3185 // C++] kviz (0) | 2023.10.07 |
[BOJ 11501 // C++] 주식 (1) | 2023.10.06 |
[BOJ 9079 // C++] 동전 게임 (1) | 2023.10.05 |