문제
상근이와 선영이가 다른 사람들이 남매간의 대화를 듣는 것을 방지하기 위해서 대화를 서로 암호화하기로 했다. 그래서 다음과 같은 대화를 했다.
- 상근: 그냥 간단히 암호화 하자. A를 1이라고 하고, B는 2로, 그리고 Z는 26으로 하는거야.
- 선영: 그럼 안돼. 만약, "BEAN"을 암호화하면 25114가 나오는데, 이걸 다시 글자로 바꾸는 방법은 여러 가지가 있어.
- 상근: 그렇네. 25114를 다시 영어로 바꾸면, "BEAAD", "YAAD", "YAN", "YKD", "BEKD", "BEAN" 총 6가지가 나오는데, BEAN이 맞는 단어라는건 쉽게 알수 있잖아?
- 선영: 예가 적절하지 않았네 ㅠㅠ 만약 내가 500자리 글자를 암호화 했다고 해봐. 그 때는 나올 수 있는 해석이 정말 많은데, 그걸 언제 다해봐?
- 상근: 얼마나 많은데?
- 선영: 구해보자!
어떤 암호가 주어졌을 때, 그 암호의 해석이 몇 가지가 나올 수 있는지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 5000자리 이하의 암호가 주어진다. 암호는 숫자로 이루어져 있다.
출력
나올 수 있는 해석의 가짓수를 구하시오. 정답이 매우 클 수 있으므로, 1000000으로 나눈 나머지를 출력한다.
암호가 잘못되어 암호를 해석할 수 없는 경우에는 0을 출력한다
문제 해석
알파벳이 될 수 있는 조건을 생각해주면 쉽게 풀 수 있는 문제입니다.
하지만 여기까지는 모두가 생각하고, DP로 적용할려고 하니 저는 조금 어려웠습니다.
우선 알파벳은 'A'~'Z'까지 26개의 문자가 있습니다.
따라서 두 숫자를 합쳐서 읽을때 26보다 크다면, 그때는 알파벳으로 표현을 할 수가 없습니다.
경우의 수는 다음과 같습니다.
- 숫자 두 개가 모두 0인 경우
- 해당 경우는 알파벳으로 해석이 불가능합니다. 따라서 0을 출력하고 프로그램을 종료해야 합니다.
- 숫자 두 개를 합칠 수 있는 경우
- 합친 숫자가 10 이상 , 26 이하일 때 가능합니다.
즉 우리는 12가 있다면, "AB"로도 읽을 수 있고, "L"로도 읽을수 있습니다.
입력 첫 글자가 0이라면 암호가 될 수 없기에, 0을 출력하고 종료합니다.
DP배열은 1차원 배열로 선언했습니다.
DP [X]는 x번째 단어를 읽을 때 만들 수 있는 단어의 수입니다.
즉 DP [3]은 3번째 단어를 읽을 때 만들 수 있는 단어의 수입니다.
여기서 중요한 점은 DP [0]과 DP [1]은 무조건 1로 초기화해줘야 합니다.
왜냐하면 첫 글자를 읽을 수 있기 때문입니다.(0이 아니라는 조건이 있기 때문에 가능)
만약에 입력이 25114라면
DP [2]는 2번째 글자까지 읽을 때 만들 수 있는 경우의 수입니다.
우선 2번째 글자는 5라서 읽을 수 있습니다.
따라서 첫 번째까지 읽는 단어의 숫자를 그대로 들고 오면 됩니다.
즉 DP [2] = DP [1]이 됩니다.
그다음 앞에 숫자와 현재 숫자를 조합해서 경우의 수를 생각해 줍니다.
25가 됩니다. 25는 알파벳으로 'Y'를 만들 수 있습니다.
따라서 25를 읽기 전까지의 단계에서 만들 수 있는 단어의 개수 + 25까지 읽는 단계에서 만들 수 있는 단어의 개수가 됩니다.
음 말이 굉장히 어렵네요
즉 간단하게 ,
DP [i]=DP [i-1] --> i번째 단어를 읽을 수 있는 경우 -> 즉 1~9 사이의 경우
DP [i]=DP [i-2]+DP [i]; -> 알파벳을 만들 수 있는 경우 -> 즉 10~26 사이 범위여야 합니다.
💻전체 코드
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
string str;
vector<int>dp;
int lim = 1000000;
void funct();
int main()
{
cin >> str;
if (str[0] == '0') //첫글자가 0이라면 암호가 될 수 없음.
{
cout << 0 << endl;
return 0;
}
dp.resize(str.size()+1,0);
dp[1]=1,dp[0]=1;
funct();
cout<<dp[str.size()]%lim<<endl;
}
void funct()
{
for (int i = 2; i <= str.size(); i++)
{
int num1 = str[i - 2] - '0',num2 = str[i - 1] - '0';
if(num1 ==0 && num2 ==0){ // 00이 된다면, 암호가 될 수 없음.
dp[str.size()]=0;
return;
}
int temp = num1 * 10 + num2;
if(num2>0){ //이전 상태를 그대로 들고옴.
dp[i]=dp[i-1];
}
if(temp>= 10 && temp<=26){ //두 글자를 만들수 있는 범위일때
dp[i]=dp[i-2]+dp[i];
}
dp[i]%=lim;
}
}
😀느낀 점
- 첫 글자가 0이면 exit(1) 같은 강제종료를 사용했는데, 런타임에러가 났다.
- 초기에는 이유를 몰라서 허둥허둥했는데, exit(1) 대신 return 0을 하니까 해결됐다.
'CodingTest > Baekjoon' 카테고리의 다른 글
[백준 20922] - 겹치는 건 싫어(C++)[실버1] (0) | 2023.04.02 |
---|---|
[백준 2470]-두 용액(C++)[골드5] (0) | 2023.04.01 |
[백준 7579] - 앱(C++)[골드3] (0) | 2023.03.25 |
[백준 17485] - 진우의 달 여행(Large)(C++)[골드5] (0) | 2023.03.24 |
[백준 2580] - 스도쿠(C++)[골드4] (0) | 2023.03.18 |