백준 2780번 (C++)
2021. 7. 30. 23:14ㆍAlgorithm/알고리즘 스터디(2021)
반응형
https://www.acmicpc.net/problem/2780
2780번: 비밀번호
각각의 Test case에 대해서 조건을 만족하는 비밀번호의 개수를 출력하라. 단, 수가 매우 커질 수 있으므로 비밀번호의 개수를 1,234,567으로 나눈 나머지를 출력하라.
www.acmicpc.net
1. 문제
석원이는 자신의 현관문에 비밀번호 기계를 설치했다. 그 기계의 모양은 아래 그림과 같다.
지나가던 석원이 친구 주희는 단순한 호기심에 저 비밀번호를 풀고 싶어한다. 이때 주희는 바닥에 떨어져 있는 힌트 종이를 줍게 된다. 이 종이에는 석원이가 비밀번호를 만들 때 사용했던 조건이 적혀 있다. 이제 주희는 이 조건을 가지고, 석원이 집의 가능한 비밀번호의 전체 개수를 알고 싶어 한다. 현재 컴퓨터를 사용할 수 없는 주희는 당신에게 이 문제를 부탁했다.
석원이의 힌트 종이는 다음과 같다.
1. 비밀번호의 길이는 N이다.
2. 비밀번호는 위 그림에 나온 번호들을 눌러서 만든다.
3. 비밀번호에서 인접한 수는 실제 위 기계의 번호에서도 인접해야 한다.
(ex. 15 라는 비밀번호는 불가능하다. (1과 5는 인접하지 않는다. ) 하지만 1236이라는 비밀번호는 가능하다.)
2. 입력 / 출력
가. 입력
첫 번째 줄에 Test case의 수 T가 주어진다. 그리고 각각의 케이스마다 입력으로 첫 번째 줄에 비밀번호의 길이 N이 주어진다.( 1 <= N <= 1,000 )
- 테스트 케이스의 수 T
- 비밀번호의 길이 N (1≤N≤1,000)
나. 출력
각각의 Test case에 대해서 조건을 만족하는 비밀번호의 개수를 출력하라. 단, 수가 매우 커질 수 있으므로 비밀번호의 개수를 1,234,567으로 나눈 나머지를 출력하라.
- 각각의 테스트 케이스에 대해서 조건을 만족하는 비밀번호의 개수
※ 비밀번호의 개수를 1,234,567로 나눈 나머지를 출력한다.
3. 알고리즘
- 키패드 모양을 고려해서 인접할 수 있는 숫자 배열을 먼저 생각한다.
-
07 12, 14 21, 23, 25 32, 36 41, 45, 47 52, 54, 56, 58 63, 65, 69 70, 74, 78 85, 87, 89 96, 98 - 비밀번호의 n번째자리에 k라는 숫자가 오려면 비밀번호의 (n-1)번째 자리에 k와 인접할 수 있는 숫자 m, n, ··· 중 하나가 와야 한다. 그러므로 다음과 같이 생각할 수 있다.
ex) array[2][2] = array[1][1] + array[1][3] + array[1][5]
4. 전체 코드
#include <stdio.h>
int main() {
int i, j, T, N, sum=0;
int array[1001][10];
int array2[1];
scanf_s("%d", &T);
for (i = 0; i < 10; i++) {
array[1][i] = 1;
}
for (i = 2; i < 1001; i++) {
for (j = 0; j < 10; j++) {
switch (j) {
case 0:
array[i][j] = array[i - 1][7];
break;
case 1:
array[i][j] = array[i - 1][2] + array[i - 1][4];
break;
case 2:
array[i][j] = array[i - 1][1] + array[i - 1][3] + array[i - 1][5];
break;
case 3:
array[i][j] = array[i - 1][2] + array[i - 1][6];
break;
case 4:
array[i][j] = array[i - 1][1] + array[i - 1][5] + array[i - 1][7];
break;
case 5:
array[i][j] = array[i - 1][2] + array[i - 1][4] + array[i - 1][6] + array[i - 1][8];
break;
case 6:
array[i][j] = array[i - 1][3] + array[i - 1][5] + array[i - 1][9];
break;
case 7:
array[i][j] = array[i - 1][0] + array[i - 1][4] + array[i - 1][8];
break;
case 8:
array[i][j] = array[i - 1][5] + array[i - 1][7] + array[i - 1][9];
break;
case 9:
array[i][j] = array[i - 1][6] + array[i - 1][8];
break;
}
}
}
for (i = 0; i < T; i++) {
scanf_s("%d", &N);
for (j = 0; j < 10; j++) {
sum += array[N][j];
}
array2[i] = sum;
sum = 0;
}
for (i = 0; i < T; i++) {
printf("%d\n", array2[i] % 1234567);
}
}
5. 코드 세부 설명
가. 변수, 배열 설정
int main() {
int i, j, T, N, sum=0;
int array[1001][10];
int array2[1];
scanf_s("%d", &T);
for (i = 0; i < 10; i++) {
array[1][i] = 1; //array[1][0] ~ array[1][9]는 1가지이다.
}
}
- i, j : 반복문을 사용하기 위한 변수
- T : 테스트 케이스의 개수
- N : 비밀번호의 길이 (1≤N≤1,000)
- sum : 조건을 만족하는 비밀번호의 개수 (처음에는 0으로 초기화 시킴.)
- array[1001][10] : 조건에 부합하는 숫자 조합을 계산하기 위한 배열
- array2[1] : N가지의 비밀번호 개수를 저장하기 위한 배열
나. 계산하는 부분
for (i = 2; i < 1001; i++) {
for (j = 0; j < 10; j++) {
switch (j) {
case 0:
array[i][j] = array[i - 1][7];
break;
case 1:
array[i][j] = array[i - 1][2] + array[i - 1][4];
break;
case 2:
array[i][j] = array[i - 1][1] + array[i - 1][3] + array[i - 1][5];
break;
case 3:
array[i][j] = array[i - 1][2] + array[i - 1][6];
break;
case 4:
array[i][j] = array[i - 1][1] + array[i - 1][5] + array[i - 1][7];
break;
case 5:
array[i][j] = array[i - 1][2] + array[i - 1][4] + array[i - 1][6] + array[i - 1][8];
break;
case 6:
array[i][j] = array[i - 1][3] + array[i - 1][5] + array[i - 1][9];
break;
case 7:
array[i][j] = array[i - 1][0] + array[i - 1][4] + array[i - 1][8];
break;
case 8:
array[i][j] = array[i - 1][5] + array[i - 1][7] + array[i - 1][9];
break;
case 9:
array[i][j] = array[i - 1][6] + array[i - 1][8];
break;
}
}
}
비밀번호의 n번째자리에 k라는 숫자가 오려면 비밀번호의 (n-1)번째 자리에 k와 인접할 수 있는 숫자 m, n, ··· 중 하나가 와야 한다.
for (i = 0; i < T; i++) {
scanf_s("%d", &N);
for (j = 0; j < 10; j++) {
sum += array[N][j];
}
array2[i] = sum;
sum = 0; //꼭 초기화해주어야 한다.
}
비밀번호의 개수 sum을 구하고 array2에 저장한다. 여러 케이스를 계산하고 그 결과를 한꺼번에 출력하기 때문이다. sum을 array2에 저장하고 나서는 꼭 초기화 해줘야 한다. 그러지 않으면 다음 케이스의 값만 출력되지 않고 그 전 케이스의 값이 더해져서 출력된다.
다. 결과 출력
for (i = 0; i < T; i++) {
printf("%d\n", array2[i] % 1234567);
}
array2값을 1,234,567로 나눈 나머지를 차례로 출력한다.
6. 에러
컴파일 했을 때 오류가 없었는데 값을 입력하고 실행시키니까 디버그 에러가 발생하였다. C++를 제대로 공부하지는 않았어서 오류의 원인이 무엇인지 잘 모르겠다. 오류의 원인을 찾으면 글을 업데이트 할 것이다.
반응형
'Algorithm > 알고리즘 스터디(2021)' 카테고리의 다른 글
백준 9251번 (C++) (0) | 2021.08.14 |
---|---|
백준 1309번 (C++) (0) | 2021.08.07 |
백준 16953번 (C++) (0) | 2021.08.06 |
백준 10164번 (C++) (0) | 2021.08.06 |
백준 1946번 (C++) (0) | 2021.07.29 |