새소식

알고리즘 문제풀이/SWEA

[SWEA] 1242번 암호코드 스캔 자바(java) 풀이

  • -

sw expert academy 1242 암호코드 스캔 자바(java) 풀이

문제 정리

  1. 암호는 총 8개의 숫자로 이루어져있다.
  2. 앞 7자리는 상품 고유의 번호를, 마지막 자리는 검증코드를 나타낸다.
  3. 검증코드 계산은 다음과 같이 한다.
    • (홀수 자리의 합 * 3 ) + 짝수 자리의 합 + 검증 코드는 10의 배수가 되어야 한다.
  4. 암호코드 숫자 하나의 길이는 최소7이며 7의 배수로 늘어날 수 있다. (각 숫자는 흰색과 파란색의 넓이 비로 표현된다)
    • 원래 9인 "0001011"의 비는 3:1:1:2이다. 2배로 늘어나게 되면 "00000011001111"이 된다. 비율은 같으므로 이도 9를 표현한다.
  5. 암호코드에 포함된 숫자들의 합을 출력한다.


문제 풀이

처음에는 문제 이해부터 힘들었습니다...
배열에 하나의 암호코드가 아니라 여러개의 암호코드가 들어있을 수 있습니다.
그때 들어있는 모든 암호코드를 숫자로 변환하여 합을 구해야합니다.
같은 암호코드가 여러줄에 걸쳐서 쓰여있는데 이 경우 모든 줄의 암호코드를 숫자로 바꿔서 더하는 것이 아니라
같은 줄 중 하나의 암호코드만 숫자로 변환하여 더해주면 됩니다!!

암호문을 2진수로 변환해서 풀어야 합니다.

  1. 숫자 암호들은 0으로 시작해서 '0101'의 패턴을 가지고 1로 끝납니다

    • 오른쪽에서 부터 탐색하여 1이 처음 나오고 그 위에 숫자가 0이라면 바코드의 우상단임을 알 수 있습니다. 이 경우만 암호코드의 값을 게산하면 같은 암호코드를 계산할 일이 없습니다.
  2. 배수는 어떻게 판단할 것인가?

    • 2 4 6 2가 나왔다고 하자. 그러면 가장 작은 수의 배수가 됨을 알 수 있습니다. (모두 1을 포함함)
    • 가장 작은 수가 2이므로 2로 나누어줘서 1232가 됨을 알 수 있습니다.
    • 오른쪽의 3수가 모두 다르므로 오른쪽의 3개의 수만 봐도 됩니다.
    • code를 다음과 같이 판별 할 수 있습니다.
      0은 3:2:1:1이다. 이중 오른쪽 3개의 수는 2:1:1이다.
      이를 s[2][1][1] = 0로 표현합니다.
      1는 s[2][2][1] = 1로 표현합니다.
      나머지 수들도 마찬가지입니다.
      integer형으로 바꾸어서 bit shift 연산을 통해 번역하지 않고 하나씩 읽어가며 할 수 있습니다.
  3. 이전 줄과 같은 줄은 입력받은 경우 스킵
    이는 구현하지 않아도 통과할 수 있습니다.
    입력을 보면 똑같은 줄이 많이 주어집니다. 이러한 경우 이전 줄과 같으면 탐색을 하지 않고 skip하게 되면 더 빠른 시간안에 답을 도출할 수 있습니다.
    skip 하는 부분을 추가함으로써 200ms 가까이 빠르게 답을 낼 수 있었습니다.

  4. 암호코드에 포함된 숫자 계산
    암호코드는 오른쪽의 3개의 수만 보면 됩니다. 이를 x,y,z 변수를 이용하여 찾습니다.
    코드는 0/1/0/1이 번갈아서 나옵니다.
    뒤에서 부터 탐색하므로 뒤의 1의 개수를 z, 뒤의 0의 개수를 y에, 앞쪽의 1의 개수를 x에 담습니다.
    이렇게 1/0/1의 각각 개수를 찾고 최소 값을 찾아서 그 값으로 나누어 주게 되면 어떤 숫자를 나타내는지 num배열을 통해 알 수 있습니다.

swea 암호코드 스캔 자바 코드

코드를 아래에 첨부하며 주석도 달아두었으니 참고하시기 바랍니다.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

class Solution {
    static char[][] map;
    static int width, height;
    static int[][][] num;
    static int ans;

    static int hcode[][] = {
        { 0, 0, 0, 0 }, //0
        { 0, 0, 0, 1 }, //1
        { 0, 0, 1, 0 }, //2
        { 0, 0, 1, 1 }, //3
        { 0, 1, 0, 0 }, //4
        { 0, 1, 0, 1 }, //5
        { 0, 1, 1, 0 }, //6
        { 0, 1, 1, 1 }, //7
        { 1, 0, 0, 0 }, //8
        { 1, 0, 0, 1 }, //9
        { 1, 0, 1, 0 }, //A
        { 1, 0, 1, 1 }, //B
        { 1, 1, 0, 0 }, //C
        { 1, 1, 0, 1 }, //D
        { 1, 1, 1, 0 }, //E
        { 1, 1, 1, 1 } //F
    };

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int testNum = Integer.parseInt(br.readLine());

        for(int test=1; test<=testNum; test++){
            String[] temp = br.readLine().split(" ");
            height = Integer.parseInt(temp[0]);
            width = Integer.parseInt(temp[1]);

            num = new int[4][3][4];
            map = new char[height][width*4];
            initCode();

            int codeLen = 7;
            int[] code = new int[8];
            ans = 0;

            // 암호
            String before = "";
            for(int i=0; i<height; i++){
                String input = br.readLine();

                // 첫 줄 or 이전 줄과 똑같을 경우 탐색 X
                if(input.equals(before) || i == 0) {
                    before = input;
                    continue;
                }

                // map 만들기
                String[] temp2 = input.split("");
                makeMap(before.split(""), i-1);
                makeMap(temp2, i);

                // 암호코드 탐색
                for(int j=width*4-1; j>0; j--){
                    // 바코드의 우상단인 경우
                    if(map[i][j] != '\0' && map[i-1][j] == '\0'){
                        int x,y,z;
                        x=y=z=0;
                        // x, y, z
                        // 1/0/1

                        // 1의 개수
                        while(map[i][j] != '\0'){
                            z++;
                            j--;
                        }
                        // 0의 개수
                        while(map[i][j] == '\0'){
                            y++;
                            j--;
                        }
                        // 1의 개수
                        while(map[i][j] != '\0'){
                            x++;
                            j--;
                        }
                        // 0의 개수
                        while(map[i][j] == '\0'){
                            j--;
                            // 맨 왼쪽은 쭉 null 문자만 나오므로 인덱스가 0에 도달하게 되면 탈출
                            if(j < 0)
                                break;
                        }
                        j++;

                        // 제일 작은 값 찾아서 나누기
                        int min = x;
                        if(min > y)
                            min = y;
                        if(min > z)
                            min = z;
                        x /= min;
                        y /= min;
                        z /= min;

                        // 찾은 숫자 쓰기
                        code[codeLen--] = num[x-1][y-1][z-1];

                        // 7개를 모두 찾음
                        if(codeLen == -1){
                            // 검증 코드 구하기
                            int odd = 0;
                            int even = 0;

                            for(int t=0; t<code.length; t++){
                                if(t % 2 == 0)
                                    even += code[t];
                                else
                                    odd += code[t];
                            }

                            int verificationCode = even*3 + odd;
                            if(verificationCode % 10 == 0)
                                ans += odd + even;
                            codeLen = 7;
                        }
                    }
                }
                before = input;
            }

            System.out.println("#" + test + " " + ans);
        }
        br.close();
    }

    public static void initCode(){
        for(int i=0; i<4; i++)
            for(int j=0; j<3; j++)
                for(int k=0; k<4; k++)
                    num[i][j][k] = -1;
        num[1][0][0] = 0;
        num[1][1][0] = 1;
        num[0][1][1] = 2;
        num[3][0][0] = 3;
        num[0][2][1] = 4;
        num[1][2][0] = 5;
        num[0][0][3] = 6;
        num[2][0][1] = 7;
        num[1][0][2] = 8;
        num[0][0][1] = 9;
    }

    public static int hexToDec(char ch){
        int num = 0;
        switch(ch){
            case 'A':
                num = 10;
                break;
            case 'B':
                num = 11;
                break;
            case 'C':
                num = 12;
                break;
            case 'D':
                num = 13;
                break;
            case 'E':
                num = 14;
                break;
            case 'F':
                num = 15;
                break;
            default:
                num = Character.getNumericValue(ch);
        }
        return num;
    }

    public static void makeMap(String[] temp2, int w) {
        for(int q=0; q<width; q++){
            int t = hexToDec(temp2[q].charAt(0));

            for(int k=0; k<4; k++)
                map[w][q*4 + k] = (char)hcode[t][k];
        }
    }
}
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.