Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/BRUTEFORCE

 

algospot.com :: BRUTEFORCE

Brute-Force Attack 문제 정보 문제 암호학에서 Brute-Force Attack 은, 암호를 풀기 위해서 무식하게 수많은 암호를 하나하나 시도하는 방법을 일컫는다. 대부분의 경우 Brute-Force Attack 을 사용하는 것은 무

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.util.*;
 
public class Main {
    private static final int MODIFIER = 1000000007;
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            int a = scanner.nextInt(), b = scanner.nextInt(), n = scanner.nextInt();
            System.out.println(solve(n, a, b));
        }
    }
 
    // logN 복잡도로 pow 연산을 수행하는 알고리즘
    private static long pow(int n, int count) {
        if (count == 0return 1;
        if (count == 1return n;
        long acc = pow(n, count / 2) % MODIFIER;
        acc = (acc * acc) % MODIFIER;
        return (count % 2 == 0) ? acc : (acc * n) % MODIFIER;
    }
 
    // min 이 max 보다 작을 때, 다음 식을 구한다.
    // n^(min) + n^(min+1) + n^(min+2) + n^(min+3) .... + n^(max)
    private static long solve(int n, int min, int max) {
        // 식을 변환 : n^(min) * (1 + n + n^2 + n^3 + ... n^(max - min))
        if (min != 0return (pow(n, min) * solve(n, 0, max - min)) % MODIFIER;
        // 기저사례 1 : max 와 min 이 동일한 경우는 1 밖에 없음.
        if (max == min) return 1;
 
        // 1 + n + n^2 ... + n^m 의 절반으로 분할 후, 아래와 같은 식으로 나눈다.
        // (1 + n + n^(m/2)) + n^(length / 2) * (1 + n + n^(m/2))
        // (1 + n + n^(m/2)) 에 해당하는 결과가 동일하게 나타나기 때문에 1 회 연산 후 합친다.
        int length = (max - min + 1);
        long acc = solve(n, min, ((max % 2 == 0) ? max - 1 : max) / 2);
        long accPow = (pow(n, length / 2* acc) % MODIFIER;
        acc = (acc + accPow) % MODIFIER;
        return (length % 2 == 0) ? acc : (acc + pow(n, length - 1)) % MODIFIER;
    }
}
cs

 

 

문제에서 요구하는 사항은 입력된 a, b, n 에 대하며 다음의 식에 대한 답을 원합니다. 

 

f(n, a, b) = n^(a) + n^(a + 1) + n^(a + 2) ..... + n^(b)

 

이 식은 중간에서 분할 후, 공통된 연산을 찾아 두번 계산하지 않는 것으로 최적화 할 수 있습니다.

 

f(n, a, b)
= n^(a) * ( 1 + n + n^2 + n^3 + .... n^(b - a))
= n^(a) * ( (1 + n + n ^2 ... n^(b - a) / 2) + n^((b - a + 1) / 2) * (1 + n + n ^2 ... n^(b - a) / 2))


해당 식을 재귀적으로 실행시키면서, 총 덧셈을 해야할 숫자의 갯수가 홀수일 때계산된 값이 오버플로우하지 않게 MOD 연산을 수행하면문제를 해결할 수 있습니다.

 

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[FENCE] 울타리 잘라내기  (0) 2022.01.14
[QUADTREE] 쿼드 트리 뒤집기  (0) 2022.01.14
[JOSEPHUS] 조세푸스 문제  (0) 2022.01.09
[CCR] 문자 인식  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/FENCE

 

algospot.com :: FENCE

울타리 잘라내기 문제 정보 문제 너비가 같은 N개의 나무 판자를 붙여 세운 울타리가 있습니다. 시간이 지남에 따라 판자들이 부러지거나 망가져 높이가 다 달라진 관계로 울타리를 통째로 교체

www.algospot.com

 

풀이입니다. 🤔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.*;
 
public class Main {
    private static final int[] fences = new int[20000];
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            int n = scanner.nextInt();
            for (int i = 0; i < n; ++i) {
                fences[i] = scanner.nextInt();
            }
 
            System.out.println(solve(fences, 0, n - 1));
        }
    }
 
    // start 와 end 구간의 fences 로 만들 수 있는 가장 큰 직사각형의 크기를 구한다.
    private static int solve(int[] fences, int startIndex, int endIndex) {
        int length = getLength(startIndex, endIndex);
        if (length == 1return fences[startIndex]; // 기저사례: 구간[start, end] 가 1일 경우, 해당 fence 를 출력.
 
        int midIndex = (startIndex + endIndex) / 2;
        // 좌-우 기준 최대값 연산
        int max = Math.max(solve(fences, startIndex, midIndex), solve(fences, midIndex + 1, endIndex));
        // 중앙 기준으로 최대값 연산
        int centerIndex = (length % 2 != 0)
                ? midIndex
                : (fences[midIndex] >= fences[midIndex + 1]) ? midIndex : midIndex + 1;
        int lIndex = centerIndex, rIndex = centerIndex;
        int minFence = fences[centerIndex];
        max = Math.max(max, minFence);
        while (inRange(lIndex - 1, startIndex, endIndex) || inRange(rIndex + 1, startIndex, endIndex)) {
            int lFence = inRange(lIndex - 1, startIndex, endIndex) ? fences[lIndex - 1] : Integer.MIN_VALUE;
            int rFence = inRange(rIndex + 1, startIndex, endIndex) ? fences[rIndex + 1] : Integer.MIN_VALUE;
            if (lFence > rFence) --lIndex;
            else ++rIndex;
            minFence = Math.min(minFence, Math.max(lFence, rFence));
            max = Math.max(max, minFence * getLength(lIndex, rIndex));
        }
 
        return max;
    }
 
    private static int getLength(int startIndex, int endIndex) {
        return endIndex - startIndex + 1;
    }
 
    private static boolean inRange(int index, int startIndex, int endIndex) {
        return startIndex <= index && index <= endIndex;
    }
}
cs


가장 기본적인 풀이로 모든 경우의 수를 탐색하는 n^2 알고리즘을 만들 수 있으나, n 이 최대 20,000 일 수 있기 때문에 시간초과가 발생합니다. 

대신에 풀 수 있는 방법 중 하나는 부분 문제를 만들어, 결과를 병합하는 분할-정복 알고리즘을 사용하는 것입니다.

 

이 알고리즘은 총 4개의 과정을 재귀로 반복합니다. 


- 울타리의 절반을 기준으로 나눈다. 
- 절반을 기준으로 왼쪽에 가장 큰 직사각형의 크기를 구한다. 

- 절반을 기준으로 오른쪽에 가장 큰 직사각형의 크기를 구한다. 
- 중앙을 기준으로 큰 울타리를 기준으로 확장해가며, 가장 큰 직사각형의 크기를 구한다. 
- 위 세 가지 과정 중 가장 큰 직사각형의 크기를 구한다. 

울타리를 절반으로 나누는 연산이 logN 번 진행되며, 그 과정에서 중앙을 기준으로 완전 탐색을 하는 n 번의 연산이 수행됩니다. 
이 알고리즘의 시간복잡도는 n*logN 입니다.

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[BRUTEFORCE] Brute-Force Attack  (2) 2022.01.17
[QUADTREE] 쿼드 트리 뒤집기  (0) 2022.01.14
[JOSEPHUS] 조세푸스 문제  (0) 2022.01.09
[CCR] 문자 인식  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/QUADTREE

 

algospot.com :: QUADTREE

쿼드 트리 뒤집기 문제 정보 문제 대량의 좌표 데이터를 메모리 안에 압축해 저장하기 위해 사용하는 여러 기법 중 쿼드 트리(quad tree)란 것이 있습니다. 주어진 공간을 항상 4개로 분할해 재귀적

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.*;
 
public class Main {
    private static final String EMPTY = "", X_HEAD = "x";
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            String tree = scanner.next();
            System.out.println(reverse(tree, 0));
        }
    }
 
    // 시작 index 부터 존재하는 트리의 모양을 뒤짚어 출력한다.
    private static String reverse(String tree, int index) {
        String head = (tree.length() <= index) ? EMPTY : String.valueOf(tree.charAt(index));
        StringBuilder ret = new StringBuilder();
        ret.append(head);
        if (head.equals(X_HEAD)) {
            int accSize = 1;
            List<String> accReverse = new ArrayList<>();
            for (int i = 0; i < 4++i) {
                String acc = reverse(tree, index + accSize);
                accSize += acc.length();
                accReverse.add(acc);
            }
            ret.append(accReverse.get(2));
            ret.append(accReverse.get(3));
            ret.append(accReverse.get(0));
            ret.append(accReverse.get(1));
        }
 
        return ret.toString();
    }
}
cs

 

문자열의 index 부터 시작하는 트리를 뒤짚는 부분문제를 생각합니다. 
큰 트리부터 재귀로 이 부분문제를 풀어나가면서 배치하도록 하면 쉽게 풀 수 있습니다. 

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[BRUTEFORCE] Brute-Force Attack  (2) 2022.01.17
[FENCE] 울타리 잘라내기  (0) 2022.01.14
[JOSEPHUS] 조세푸스 문제  (0) 2022.01.09
[CCR] 문자 인식  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://algospot.com/judge/problem/read/JOSEPHUS

 

algospot.com :: JOSEPHUS

조세푸스 문제 문제 정보 문제 1세기에 살던 역사학자 조세푸스는 로마와의 전쟁에서 패해 N - 1명의 동료 병사들과 함께 출구가 없는 동굴에 포위당했다고 합니다. 동료 병사들은 로마에 항복하

algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Queue<Integer> queue = new ArrayDeque<>();
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            int n = scanner.nextInt(), k = scanner.nextInt();
            for (int i = 1; i <= n; ++i) queue.offer(i);
            while (queue.size() > 2) {
                queue.poll();
                for (int i = 0, len = k - 1; i < len; ++i) queue.offer(queue.poll());
            }
 
            int first = queue.poll(), second = queue.poll();
            System.out.printf("%d %d\n", Math.min(first, second), Math.max(first, second));
        }
    }
}
cs

 

Queue 를 이용하면 문제를 쉽게 해결할 수 있습니다.

최종 2명이 남을 때까지 Queue 에서 1회 선출, k-1 회 선출 후 재입력을 하게 되면 마지막까지 생존한 2명을 구할 수 있습니다. 

 

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[FENCE] 울타리 잘라내기  (0) 2022.01.14
[QUADTREE] 쿼드 트리 뒤집기  (0) 2022.01.14
[CCR] 문자 인식  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
[WORDLENGTH] 단어 길이 재기  (0) 2022.01.07
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/CCR

 

algospot.com :: CCR

문자 인식 문제 정보 문제 DCinside에 알고리즘 갤러리가 생겼다! 그러나 알고리즘 갤러리는 수많은 수갤러스(수능 갤러리 유저)들의 공격을 받곤 했는데, 수학 I 교과목에서 가장 쉬운 부분이 알

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import java.util.Scanner;
 
public class Main {
    private static final char STAR = '*', BLANK = '_';
    private static final char[][] board = new char[25][81];
    private static final int[] PLACE = {00}, TOP = {-10}, RIGHT = {01}, BOTTOM = {10}, LEFT = {0-1};
    private static final int[][] directions = new int[][]{TOP, RIGHT, BOTTOM, LEFT};
    private static int r, c;
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            r = scanner.nextInt();
            c = scanner.nextInt();
            for (int i = 0; i < r; ++i) {
                String line = scanner.next();
                for (int j = 0; j < c; ++j) board[i][j] = line.charAt(j);
            }
 
            int ret = 0;
            for (int y = 0; y < r; ++y) {
                for (int x = 0; x < c; ++x) {
                    if (board[y][x] != STAR) continue;
                    if (!hasStar(y, x, RIGHT)) ret += get14(y, x);
                    else {
                        if (hasStar(y, x, BOTTOM)) ret += get05689(y, x);
                        else ret += get237(y, x);
                    }
 
                    clearStar(y, x);
                }
            }
 
            System.out.println(ret);
        }
    }
 
    private static int getEndOfStarCount(int y, int x, int[] direction) {
        int ret = 0;
        for (int ny = y, nx = x; hasStar(ny, nx, direction); ny += direction[0], nx += direction[1]) {
            ++ret;
        }
        return ret;
    }
 
    private static boolean hasStar(int y, int x, int[] direction) {
        int ny = y + direction[0], nx = x + direction[1];
        return ny >= 0 && ny < r && nx >= 0 && nx < c && board[ny][nx] == STAR;
    }
 
    private static void clearStar(int y, int x) {
        board[y][x] = BLANK;
        for (int[] direction : directions) {
            int ny = y + direction[0], nx = x + direction[1];
            if (hasStar(ny, nx, PLACE)) clearStar(ny, nx);
        }
    }
 
    private static int get05689(int y, int x) {
        int endOfRightCount = getEndOfStarCount(y, x, RIGHT);
        int ny = y + RIGHT[0* endOfRightCount, nx = x + RIGHT[1* endOfRightCount;
        if (hasStar(ny, nx, BOTTOM)) {
            return get089(y, x, y + getEndOfStarCount(ny, nx, BOTTOM));
        } else {
            return get56(y, x);
        }
    }
 
    private static int get089(int y, int x, int endOfY) {
        int ny = y, nx = x, rightCount = 0;
        while (hasStar(ny, nx, BOTTOM)) {
            ny += BOTTOM[0]; nx += BOTTOM[1];
            if (hasStar(ny, nx, RIGHT)) ++rightCount;
        }
 
        if (ny != endOfY) return 9;
        else {
            switch (rightCount) {
                case 1return 0;
                case 2return 8;
                defaultthrow new IllegalArgumentException();
            }
        }
    }
 
    private static int get56(int y, int x) {
        int ny = y, nx = x, rightCount = 0;
        while (hasStar(ny, nx, BOTTOM)) {
            ny += BOTTOM[0]; nx += BOTTOM[1];
            if (hasStar(ny, nx, RIGHT)) ++rightCount;
        }
 
        switch (rightCount) {
            case 1return 5;
            case 2return 6;
            defaultthrow new IllegalArgumentException();
        }
    }
 
    private static int get237(int y, int x) {
        int endOfRightCount = getEndOfStarCount(y, x, RIGHT);
        int ny = y + RIGHT[0* endOfRightCount, nx = x + RIGHT[1* endOfRightCount, leftCount = 0;
        while (hasStar(ny, nx, BOTTOM)) {
            ny += BOTTOM[0]; nx += BOTTOM[1];
            if (hasStar(ny, nx, LEFT)) ++leftCount;
        }
 
        switch (leftCount) {
            case 0return 7;
            case 1return 2;
            case 2return 3;
            defaultthrow new IllegalArgumentException();
        }
    }
 
    private static int get14(int y, int x) {
        int ny = y, nx = x;
        while (hasStar(ny, nx, BOTTOM)) {
            ny += BOTTOM[0]; nx += BOTTOM[1];
            if (hasStar(ny, nx, RIGHT) || hasStar(ny, nx, LEFT)) return 4;
        }
 
        return 1;
    }
}
cs

 

문제의 내용 중 주의할 내용은 아래와 같습니다. 

 

문자들은 바로 옆에 인접하지 않으므로 연속된 검은 색 격자칸들의 집합이 어떠한 문자도 표현하지 않는 잘못된 경우는 존재하지 않는다.

 

숫자를 인식하기 위해 모든 특징에 맞춰 격자칸들의 집합을 순회하는 것이 아닌, 문자에 존재하는 특이점을 이용해서 인식하도록 한다면 쉽게 문제를 해결해볼 수 있습니다. 
특이점의 예시는 다음과 같습니다.

- 1 과 4 의 경우는 시작점의 오른쪽에는 격자가 존재하지 않습니다. 
- 2, 3 그리고 7은 시작점의 오른쪽에는 격자가 존재하지만 아래쪽에는 존재하지 않습니다.
- 5 와 6 의 시작점으로 오른쪽 끝 격자로부터 아래칸은 존재하지 않습니다.
- ....

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[QUADTREE] 쿼드 트리 뒤집기  (0) 2022.01.14
[JOSEPHUS] 조세푸스 문제  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
[WORDLENGTH] 단어 길이 재기  (0) 2022.01.07
[MVP] Most Valuable Programmer  (0) 2022.01.07
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/SPETIAL

 

algospot.com :: SPETIAL

Spatial Concepts Test 문제 정보 문제 The Flathead Testing Corporation (FTC) supplies various tests for Human Resources departments at many companies. One type of test they supply includes spatial concepts questions such as: When the following figure

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.io.*;
 
public class Main {
    // [1] 이 (x - 1)이고, [1] 의 orientation 1 이 (y-1)일 때, [2] 의 Face 와 [1] 과 접촉 orientation
    private static final int[][][] ROTATIONS = new int[][][]{
            {{10}, {40}, {30}, {20}},
            {{41}, {03}, {23}, {53}},
            {{11}, {02}, {33}, {50}},
            {{21}, {01}, {43}, {51}},
            {{31}, {00}, {13}, {52}},
            {{12}, {22}, {32}, {42}}
    };
 
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        Face[] cube = new Face[6];
        Face[] answers = new Face[3];
        boolean[] ret = new boolean[5];
        int testCases = Integer.parseInt(reader.readLine());
        for (int testCase = 1; testCase <= testCases; ++testCase) {
            readFaces(cube, reader.readLine());
 
            int answerCount = 0;
            for (int i = 0, len = ret.length; i < len; ++i) {
                readFaces(answers, reader.readLine());
                ret[i] = isAnswer(cube, answers);
                if (ret[i]) ++answerCount;
            }
 
            System.out.printf("%d %d %c %c %c %c %c\n",
                    testCase,
                    answerCount,
                    getTrueOrFalse(ret[0]),
                    getTrueOrFalse(ret[1]),
                    getTrueOrFalse(ret[2]),
                    getTrueOrFalse(ret[3]),
                    getTrueOrFalse(ret[4])
            );
        }
    }
 
    private static void readFaces(Face[] buffer, String fold) {
        for (int i = 0, len = fold.length(); i < len; i+=2) {
            buffer[i / 2= new Face(fold.charAt(i), fold.charAt(i + 1- '1');
        }
    }
 
    private static boolean isAnswer(Face[] cube, Face[] answer) {
        boolean ret = false;
        for (int i = 0, faceLength = cube.length; i < faceLength && !ret; ++i) {
            // [1] 영역 검증 및 회전횟수 연산
            if (cube[i].shape != answer[0].shape) continue;
            // cube 의 orientation 과 answer 의 orientation 비교하여 [1] 의 1위치를 구한다.
            // f(cube, answer) = rotation
            // f(0, 0) = 0, f(0, 1) = 3, f(0, 2) = 2, f(0, 3) = 1
            // f(2, 2) = 0, f(2, 3) = 3, f(2, 0) = 2, f(2, 1) = 1
            int rotation = (4 + cube[i].orientation - answer[0].orientation) % 4;
 
            // [2] 영역 검증
            int[] right = ROTATIONS[i][rotation];
            if (cube[right[0]].shape != answer[1].shape) continue;
            if ((cube[right[0]].orientation - right[1+ 4) % 4 != answer[1].orientation) continue;
 
            // [3] 영역 검증
            int[] left = ROTATIONS[i][(rotation + 1) % 4];
            if (cube[left[0]].shape != answer[2].shape) continue;
            if ((cube[left[0]].orientation + 3 - left[1]) % 4 != answer[2].orientation) continue;
 
            // 모든 검증이 통과한다면, 정답 처리
            ret = true;
        }
 
        return ret;
    }
 
    private static char getTrueOrFalse(boolean ret) {
        return ret ? 'Y' : 'N';
    }
 
    private static final class Face {
        final char shape;
        final int orientation;
 
        public Face(char shape, int orientation) {
            this.shape = shape;
            this.orientation = orientation;
        }
    }
}
cs

 

문제가 특별한 알고리즘 기술을 요구하는 것은 아니지만, 펼쳐진 직육면체에 대해 보여지는 단면을 나타내도록 하는 것이 쉽지 않았습니다. 
어려운 문제를 분리해서 각 단계마다 해결해나가는 것이 중요한 문제라 생각합니다. 

 

1. [1] 면에 대한 후보 탐색 및 회전 횟수 구하기

 

기준이 되는 [1] 면을 찾기 위해, 직육면체의 면(cube)들과 정답의 첫번째 면(answer[0])모양(shape)이 동일한 것을 탐색합니다. 

동일한 모양을 찾았다면, 현재의 회전 상태를 [1] 면의 1번을 기준으로 연산합니다. 

예를들어 Cube F3E4E2D3C2F3 가 입력이 되었을 때 예상되는 정답 C2D2F2 가 입력되었다면, 첫번째 정답 면 C2 의 모양 C 는 Cube 의 5번째 면 C2 와 동일하기 때문에 [1] 은 5번째 면이 됨을 알 수 있습니다. 

첫번째 예상되는 정답 면은 정위는 2, 5번째 면의 정위는 2 이기 때문에 현재 직육면체는 5번째 면의 1 을 기준으로 앞에 표시되고 있습니다. 
입력된 직육면체의 면이 3이고, 예상되는 정답의 면이 4이면 어떨까요?

시계방향으로 한번 회전했기 때문에 [1] 의 1 은 4를 기준으로 표시됩니다.

입력된 직육면체의 면이 3이고, 예상되는 정답의 면이 1이면 어떨까요?

시계방향으로 두번 회전했기 때문에 [1] 의 1 은 3를 기준으로 표시됩니다.

 

수학적 귀납법으로 직육면체 면의 정위가 x, 예상되는 정위가 y 라 할 때 [1] 의 1 은 어떤 기준으로 나타낼지 알아볼 수 있습니다.

이는 다음과 같은 식으로 정의 됩니다. 

 

f(x, y) = (4 + x - y) % 4

 

 

2. 회전 횟수에 근거하여, [2] 면에 대한 정보 검증 

 

앞에서, [1] 면의 후보와 표시되는 정위를 구할 수가 있었습니다. 

이를 바탕으로, [2] 면의 표시되는 정보를 알 수 있습니다. 
미리 선언한 배열 ROTATIONS 은 [1] 면이 x 이고 정위 1 이 y 로 표시될 때 [2] 면의 직육면체면의 번호와 x면과 접촉하는 정위입니다. 

예를들어 Cube F3E4E2D3C2F3 가 입력이 되었을 때 예상되는 정답 C2D2F2 가 입력되었고, [1]면이 5번째(C2), 정위 1을 기준으로 표시하고 있기 때문에 [2] 면은 4번째(D3)이며 5번째 면과 접촉된 정위는 2입니다.

 

ROTATIONS[4][0] = {3, 1}

 

배열에 존재하는 직육면체 번호를 이용하여 [2] 의 모양 검증 거친 후, [1] 과 접촉된 정위를 [2] 의 정위 1 이 되도록 회전시킵니다. 

앞의 예시에서 4번째 접촉면은 2 이며, [2] 의 1 은 2를 기준으로 표시하고 있습니다. 

 

 

3. 회전 횟수에 근거하여, [3] 면에 대한 정보 검증

 

마지막 단계는 서술된 2번의 단계와 유사합니다.

[3] 의 면은 [2] 의 면 옆에 있기 때문에 앞단계에서 선택된 ROTATIONS 의 다음이라 생각할 수 있습니다. 

예를들어 앞단계에서 ROTATIONS[4][0] 이 선택되었는데 [3] 면은 [2] 면의 옆에 있으니, ROTATIONS[4][1] 로 볼 수 있습니다.

 

이 후 단계는 서술된 2의 단계와 동일하지만, 표시하는 상단 기준이 1에서 4로 변경되었기 때문에 이 부분만 조금 변경하면 정답 검증을 해볼 수 있습니다. 

예를들어 Cube F3E4E2D3C2F3 가 입력이 되었을 때 예상되는 정답 C2D2F2 가 입력되었고, [1]면이 5번째(C2), 정위 1을 기준으로 표시하고 있고 때문에 [2] 면은 4번째(D3)이며 5번째 면과 접촉된 정위는 2일 때, [3]면은 1번째(F3)이며 5번째 면과 접촉된 정위는 1입니다.
접촉된 정위 1 을 [3] 의 4 를 기준으로 맞춰 검증해봅니다.

 

 


문제 해결을 위해 머릿속으로만 구상을 해보면, 쉽지가 않은 문제였습니다. 

A4 용지와 펜을 준비하여 직접 정육면체를 그려보고, 회전을 시켜보며 각각의 단계에 해당하는 요구사항을 만들어 일반화를 시킨다면, 충분히 이해하고 풀 수 있을 것이라 생각합니다. 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[JOSEPHUS] 조세푸스 문제  (0) 2022.01.09
[CCR] 문자 인식  (0) 2022.01.09
[WORDLENGTH] 단어 길이 재기  (0) 2022.01.07
[MVP] Most Valuable Programmer  (0) 2022.01.07
[MISPELL] Mispelling  (0) 2022.01.06
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/WORDLENGTH

 

algospot.com :: WORDLENGTH

단어 길이 재기 문제 정보 문제 (주의: 이 문제는 TopCoder SRM 202 Div 1 Easy 의 번역입니다) 단어들의 길이는 어떤 문장이 어렵게 쓰여진 문장인지, 쉬운 문장인지를 가르는 데 좋은 척도가 됩니다. 예

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
    private static final char HYPHEN = '-';
    private static final char BLANK = ' ';
 
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int cases = Integer.parseInt(in.readLine());
        while (cases-- > 0) {
            StringBuilder builder = new StringBuilder();
            int n = Integer.parseInt(in.readLine());
            for (int i = 0; i < n; ++i) {
                String line = calibrateInputString(in.readLine());
                for (int j = 0, len = line.length(); j < len; ++j) {
                    int curSize = builder.length();
                    char c = calibrateCharAt(line, j, i + 1 == n);
                    switch (c) {
                        case BLANK:
                        case HYPHEN:
                            if (curSize != 0) {
                                if (isAlphabet(builder.charAt(curSize - 1))) builder.append(c);
                                else builder.setCharAt(curSize - 1, BLANK);
                            }
                            break;
 
                        default:
                            if (curSize == 0 || builder.charAt(curSize - 1!= HYPHEN) builder.append(c);
                            else builder.setCharAt(curSize - 1, c);
                    }
                }
            }
 
 
            String[] words = builder.toString().trim().split(String.valueOf(BLANK));
            double ret = 0;
            if (words.length != 0) {
                for (String word : words) ret += word.length();
                ret /= words.length;
            }
 
            System.out.printf("%.3f\n", ret);
        }
 
        in.close();
    }
 
    private static String calibrateInputString(String line) {
        // line 의 마지막이 Alphabet 이라면, 단어의 끝으로 봐야한다.
        return (!line.isEmpty() && isAlphabet(line.charAt(line.length() - 1))) ? line + BLANK : line;
    }
 
    private static char calibrateCharAt(String str, int index, boolean isEndOfLine) {
        char c = str.charAt(index);
        if (c != HYPHEN) return c;
        return (index + 1 == str.length() && !isEndOfLine) ? HYPHEN : BLANK;
    }
 
    private static boolean isAlphabet(char c) {
        return c >= 'a' && c <= 'z';
    }
}
cs

 

어려운 문제는 아니지만, 주의해야할 테스트 케이스가 있습니다. 
기본 예제와 더불어 아래 테스트 케이스도 통과하는지 살펴볼 필요가 있습니다.

 

5
hello-$
there-$
world$
4
a-$
-$
-$
b$
3
i am ver-$
y sleepy arent-$
 you$
1
jong-man rules$
4
a$ 
b-$
c-$
d$
// [a, bcd]

(주의 : 위 입력의 $ 기호는 줄바꿈을 보여주기 위해 추가한 것이며, 실제 입력에는 존재하지 않습니다.  )

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[CCR] 문자 인식  (0) 2022.01.09
[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
[MVP] Most Valuable Programmer  (0) 2022.01.07
[MISPELL] Mispelling  (0) 2022.01.06
[DIAMOND] 다이아몬드  (0) 2022.01.06
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/MVP

 

algospot.com :: MVP

Most Valuable Programmer 문제 정보 문제 The season of professional programming league has just ended and it’s time for the MVP(Most Valuable Programmer) voting! There are n newspapers reporters who can vote, and the number of candidate programmers

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.util.*;
 
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
 
        int[][] prefers = new int[100][10];
        int[] votes = new int[10], positions = new int[100];
        boolean[] eliminated = new boolean[10];
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            int n = scanner.nextInt(), m = scanner.nextInt();
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    prefers[i][j] = scanner.nextInt() - 1;
                }
            }
 
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    int prefer = -1;
                    while (positions[j] < m && prefer == -1) {
                        // 이 부분 구현을 위해 Queue 를 사용해도 좋다.
                        // 이 코드에서는 제거된 프로그래머를 제외하기 위해 prefers 의 Position 만을 제어하고 있다.
                        if (eliminated[prefers[j][positions[j]]]) ++positions[j];
                        else prefer = prefers[j][positions[j]];
                    }
 
                    if (prefer != -1++votes[prefer];
                }
 
                int minVote = Integer.MAX_VALUE, minCount = 0, clearedCount = 0;
                for (int j = 0; j < m; ++j) {
                    if (eliminated[j]) ++clearedCount;
                    else {
                        if (minVote == votes[j]) ++minCount;
                        else if (minVote > votes[j]) {
                            minCount = 1;
                            minVote = votes[j];
                        }
                    }
                }
                if (m - clearedCount != minCount) {
                    for (int j = 0; j < m; ++j) if (votes[j] == minVote) eliminated[j] = true;
                }
 
                Arrays.fill(votes, 0);
            }
 
            List<Integer> answers = new ArrayList<>();
            for (int i = 0; i < m; ++i) if (!eliminated[i]) answers.add(i + 1);
            for (int i = 0, size = answers.size(); i < size; ++i) {
                System.out.printf("%d%s", answers.get(i), (i + 1 == size) ? "\n" : " ");
            }
 
            Arrays.fill(eliminated, false);
            Arrays.fill(positions, 0);
        }
    }
}
cs

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[SPETIAL] Spatial Concepts Test  (0) 2022.01.09
[WORDLENGTH] 단어 길이 재기  (0) 2022.01.07
[MISPELL] Mispelling  (0) 2022.01.06
[DIAMOND] 다이아몬드  (0) 2022.01.06
[ENCODING] Encoding  (0) 2022.01.06
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/MISPELL

 

algospot.com :: MISPELL

Mispelling 문제 정보 문제 Misspelling is an art form that students seem to excel at. Write a program that removes the nth character from an input string. 입력 The first line of input contains a single integer N, (1 ≤ N ≤ 1000) which is the numb

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int cases = scanner.nextInt();
        for (int i = 1; i <= cases; ++i) {
            int number = scanner.nextInt();
            String character = scanner.next();
 
            System.out.printf("%d ", i);
            for (int j = 0, size = character.length(); j < size; ++j) {
                if (j + 1 != number) System.out.print(character.charAt(j));
            }
            System.out.println();
        }
    }
}
cs

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[WORDLENGTH] 단어 길이 재기  (0) 2022.01.07
[MVP] Most Valuable Programmer  (0) 2022.01.07
[DIAMOND] 다이아몬드  (0) 2022.01.06
[ENCODING] Encoding  (0) 2022.01.06
[CANDLESTICK] Candlestick Charts  (0) 2022.01.06
Posted by N'

Java 로 풀어보는 알고리즘입니다. 📖
코딩테스트를 대비하여 JAVA1.8 부터 제공되는 함수형 API 는 사용하지 않았습니다.

문제 : https://www.algospot.com/judge/problem/read/DIAMOND

 

algospot.com :: DIAMOND

다이아몬드 문제 정보 문제 ......#............................ ..#.######......................... .##########..........###........... ..#.#########......#######......... ......#............#######......... ....................####.#......... ...

www.algospot.com

 

풀이입니다. 🤔

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.util.*;
 
public class Main {
    private static final char SHARP = '#';
    private static final char[][] board = new char[50][50];
 
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
 
        int cases = scanner.nextInt();
        while (cases-- > 0) {
            int h = scanner.nextInt(), w = 0;
            for (int i = 0; i < h; ++i) {
                String line = scanner.next();
                w = line.length();
                for (int j = 0; j < w; ++j) {
                    board[i][j] = line.charAt(j);
                }
            }
 
            int ret = 0;
            for (int i = 0; i < h; ++i) {
                for (int j = 0; j < w; ++j) {
                    ret = Math.max(ret, getMaxDiamondLength(i, j, h, w));
                }
            }
 
            System.out.println(ret);
        }
    }
 
    private static int getMaxDiamondLength(int y, int x, int h, int w) {
        int ret = 0, safety = 0;
        for (int goal = 1; goal <= h; goal += 2) {
            int center = goal / 2;
            for (int distance = safety; distance < goal; ++distance) {
                if (y + distance >= h
                        || !hasLine(y + distance, x, w, (distance > center) ? goal - distance - 1 : distance)) {
                    return ret;
                }
            }
 
            ret = goal;
            safety = center; // 다이아몬드가 있는 것이 증명되었다면, 다음 회차에서 Center 까지는 정확한 # 이 존재함을 보장한다.
        }
        return ret;
    }
 
    private static boolean hasLine(int y, int x, int w, int distance) {
        int startX = x - distance, endX = x + distance;
        if (startX < 0return false;
        if (endX >= w) return false;
 
        for (int i = startX; i <= endX; ++i) if (board[y][i] != SHARP) return false;
        return true;
    }
}
cs이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

 

 

이 포스트를 읽어주셔서 감사합니다. 🙇🏻‍♂️

반응형

'개발이야기 > 알고스팟' 카테고리의 다른 글

[MVP] Most Valuable Programmer  (0) 2022.01.07
[MISPELL] Mispelling  (0) 2022.01.06
[ENCODING] Encoding  (0) 2022.01.06
[CANDLESTICK] Candlestick Charts  (0) 2022.01.06
[KAKURO1] Kakuro I  (0) 2022.01.06
Posted by N'