1240. [S/W 문제해결 응용] 1일차 - 단순 2진 암호코드
배열 중간에 암호코드가 등장한다. 이 암호코드는 7자리씩 총 8개의 숫자로 이루어져있다. 이때, 마지막 숫자는 검증코드인데 이 검증코드가 유효한지 정해진 규칙에 따라 확인한다. 유효하다면 각 자리 숫자의 합을 출력하고, 유효하지 않다면 0을 출력한다.
각 숫자는 7bit의 이진수로 주어진다. 그런데 단순히 2진수->10진수
로 변환시켜 사용하는 것이 아니고, 주어진 그림을 활용해서 일치하는 숫자를 찾아내야한다.
그림으로 표시된 숫자를 활용해서 각 숫자의 값을 배열에 저장한다. initNumber()
입력받는다. String으로 한 줄씩 입력받았다. input()
2-1. 1
이 나오면 암호코드의 시작으로 이해하고 최대 56자리까지 확인해서 input
이라는 문자열에 저장했다. (지금보니 함수병이랑 변수명이 같네.. 무슨 일ㅜㅜ)
2-2. 암호코드를 저장한 다음에는 isDone=true;
로 표시해주고, 남은 입력은 형식상 받아줬다. 배열로 다 받은 다음 암호코드를 찾을 수도 있지만 메모리낭비같아서 이렇게 했다.
암호코드를 String에 저장했으므로 비트연산의 shift연산 느낌을 내기 위해 main함수에서 for문
을 돌렸다.
3-1. 암호코드의 앞 또는 뒤에 0
이 더 붙어있다. 그런데 앞에 붙었는지 뒤에 붙었는지 모르기 때문에 일단 맨 앞이 1
인 것으로 시작하고, 맨뒤에 남은 0
의 개수만큼 오른쪽으로 한칸씩 shift하는 효과를 냈다.
3-2. 7번 반복 : 가장 많이 shift하는 경우가 1000000
~ 0000001
이기 때문에 최대 7번
3-3. answer > 0
이면 검증코드가 유효하다는 것 ! 바로 출력하면 된다.
함수명 | 설명 |
---|---|
setPassword(i) | i가 오른쪽으로 몇 칸 밀리는지를 알려준다. shift한 암호코드를 배열에 갱신한다. |
getCode() | 검증코드의 유효성을 검사한다. |
getRealNum | 비트연산자 ^ 를 이용해서 서로 일치하면 해당되는 숫자를 반환한다. (지금보니 if (password == number[i]) 로 해도 되는데 ㅎㅎ.. 비트연산자가 써보고 싶었던 걸로~) |
import java.util.Scanner;
import java.io.FileInputStream;
class Solution
{
static String input ="";
static int [] passwords = new int[8];
static int [] number = new int[10];
public static void main(String args[]) throws Exception
{
initNumber();
System.setIn(new FileInputStream("res/input (23).txt"));
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
sc.nextLine();
for(int test_case = 1; test_case <= T; test_case++)
{
input(sc);
int answer = 0;
for (int i=0; i<7; i++) {
setPassword(i);
answer = getCode();
if (answer > 0) break;
if (input.charAt(55-i) == '1') break; // 끝까지 다 밀었다.
}
System.out.printf("#%d %d\n", test_case, answer);
}
}
/**
* 암호코드를 구성하는 숫자 설정
*/
static void initNumber() {
number[0] = Integer.parseInt("0001101", 2);
number[1] = Integer.parseInt("0011001", 2);
number[2] = Integer.parseInt("0010011", 2);
number[3] = Integer.parseInt("0111101", 2);
number[4] = Integer.parseInt("0100011", 2);
number[5] = Integer.parseInt("0110001", 2);
number[6] = Integer.parseInt("0101111", 2);
number[7] = Integer.parseInt("0111011", 2);
number[8] = Integer.parseInt("0110111", 2);
number[9] = Integer.parseInt("0001011", 2);
}
static void input(Scanner sc) {
input = "";
boolean isDone = false; // 암호코드 찾았는지 여부
int r = sc.nextInt();
int c = sc.nextInt();
sc.nextLine();
for (int i=0; i<r; i++) {
String str = sc.nextLine();
if (isDone) continue; // 이미 암호코드를 저장했음.
// 암호코드를 찾으러 가는 여정
for (int j=0; j<c; j++) {
if (str.charAt(j) == '0') continue;
// 첫 1 등장 == 암호코드 등장
for (int size = 0; size<56; size++) {
if ((j+size)>=c) break; // out of range
input += str.charAt(j+size);
}
isDone = true;
break;
}
}
}
/**
* number[]과 비교하여 문제에서 주어진 숫자로 변환한다.
* @param password 코드의 8개의 숫자 중 현재 확인할 숫
* @return 변환된 숫자 (0~9)
*/
static int getRealNum(int password) {
for (int i=0; i<10; i++) {
if ((password^number[i]) == 0) return i;
}
return -1;
}
/**
* 가능한 암호를 passwords 배열에 갱신해준다.
* @param turn 몇 번째인지를 받아서 shift 효과를 냄
*/
static void setPassword(int turn) {
String str;
int start = 7-turn;
str = input.substring(0, start);
passwords[0] = getRealNum(Integer.parseInt(str, 2));
for (int i=0; i<7; i++) {
str = input.substring(start, start+7);
passwords[i+1] = getRealNum(Integer.parseInt(str, 2));
start += 7;
}
}
/**
* 검증코드가 유효한지 확인함.
* @return 유효하면 각 자리의 수를 합한 결과 / 유효하지 않으면 0
*/
static int getCode() {
int answer = 0;
answer = (passwords[0]+passwords[2]+passwords[4]+passwords[6])*3 + (passwords[1]+passwords[3]+passwords[5]) + passwords[7];
if (answer%10 != 0) return 0; // 유효하지 않음
answer = 0;
for (int i=0; i<8; i++) answer += passwords[i];
return answer; // 합한 결과
}
}
되게 복잡하게 푼 것 같다.
간단하게 설명하는 능력을 키우고 싶다.
다음 이미지와 같이 모든 2진수 숫자가 1
로 끝난다. 따라서 풀이에서 3번(shift느낌)이 필요가 없었다! 그냥 뒤에서 첫 번째로 나오는 1을 암호코드의 끝으로 맞추면 된다.