2. 배열에 표시하기


생각

1단계. 25 x 25의 배열 선언

2단계. 각 원소에 인접함의 유무를 저장함

ex) 4 x 4 일때


A  A  A  S     ->        0   1   2   3

A  E  E  A     ->        4   5   6   7

A  Y  E  A     ->        8   9  10  11

A  A  A  A     ->       12  13  14 15

이면 


arr[15][15] = 

    0  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15

0      1          4  5 

1  0      2      4  5  6

2      1      3      5  6  7

3          2              6  7

4  0  1              5          8  9

5  0  1  2      4      6      8  9  10

6      1  2  3      5      7      9  10  11

7          2  3          6              10  11

8                  4  5              9              12  13

9                  4  5  6      8      10        12  13  14

10                    5  6  7      9        11        13  14  15

11                        6  7          10                    14  15

12                                8  9                    13

13                                8  9  10        12        14

14                                    9  10  11        13        15

15                                        10  11              14


3단계. 찾고자하는 문자열을 위의 인덱스로 변환후 저장한다.

ex) YES -> 9 6 3

      YEA -> 9 10 11

4단계. 저장한 숫자 배열(편의상 YES배열 )을 순회하며 arr[ i ][ i+1 ]에 YES의 (i+1)번째 요소가 들어있는지 검사한다.  있으면 i++ 후 i가 숫자 배열의 끝일때까지 반복

ex) YES -> ( arr[YES[i] ][ YES[i+1] ] == 6) 


문제


처음 위 알고리즘을 생각했을땐 2차원 배열을 가장먼저 만들어 놓기만 하면 모든 답을 처리할수 있기에 시간적인 문제를 해결할 수 있을 것이라 생각했다. 때문에 정답이라고 생각했는데 다음과 같은 경우에 답을 찾지 못하는 문제가 있다.


A  A  A  A     ->        0   1   2   3

A  E  E  E     ->        4   5   6   7

A  Y  A  A     ->        8   9  10  11

A  A  A  A     ->       12  13  14 15


일때  E E E Y의 경우 숫자배열에 5 6 5 9 로 저장되어야 함이 맞다. 하지만 위의 알고리즘은 숫자 배열을 만들때 

8방향 탐색을 하지 않는다. 때문에 7의 E를 저장하고 다음 요소인 Y를 찾을 수 없어 오답처리된다.


다른 방법을 찾아야겠다.

'All > Algorithm' 카테고리의 다른 글

FIBONACCI_문제  (0) 2015.12.28
BOGGLEGAME_알고리즘_3  (0) 2015.12.28
BOGGLEGAME_알고리즘_1  (0) 2015.12.28
BOGGLEGAME_문제  (0) 2015.12.28
ZEROONE_알고리즘  (0) 2015.12.28

1. 무식하게 풀기


생각

1단계. 먼저 5 x 5 배열에 문자열을 입력받는다.

2단계. 그후 검사할 문자열들을 N개 입력 받는다.

3단계. 입력받은 각 문자열의 문자들이 서로 인접하고 있는지를 판단하는 함수를 호출 true면 YES, false면 NO 출력

함수 내용 

 - bool f(int x,  int y,  char curCharacter) 

 - x 또는 y가 범위 0 <= (x, y) < 5 가 아니라면 false

 - 배열의 [y][x] 인덱스에 있는 문자가 찾아야 할 문자가 아니면 false

 - 해당 인덱스의 문자가 찾는 문자이고 문자열의 길이가 1이라면 true

 - 해당 인덱스의 문자가 찾는 문자이고 문자열의 길이가 1이 아니라면 다음 문자를 인접하는 8방향의 x, y와 다음 문자를 인자로 f함수 재귀 호출

 - 찾는 문자가 문자열의 마지막 문자이면 모두 찾은 것이므로 true


코드

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// BOGGLEGAME_1
#include <iostream>
#include <string.h>
static const int BOGGLE_MAX = 5;
static const int WORD_MAX = 10;
int g_ArrX[] = { -101110-1-1 };
int g_ArrY[] = { -1-1-101110 };
char* g_Boggle[BOGGLE_MAX];
char* g_WordsArr[WORD_MAX];
int g_StringLen = 0;
int g_CurCharNum = 0;
int g_CurWordNum = 0;
 
// 해당 좌표에 전달되는 문자가 있는지 검사
bool f(int y, int x, char CurChar)
{
    // 기저사례 1 x또는 y가 범위 밖이라면 false
    if (x < 0 || y < 0)     
        return false;
    // 기저사례 1 x또는 y가 범위 밖이라면 false
    if (x >= BOGGLE_MAX || y >= BOGGLE_MAX)     
        return false;
    // 기저사례 2 찾으려는 문자가 '\0' 이거나
    // 문자열의 길이와 같으면 문자열을 찾은것이므로 true
    if (CurChar == '\0' || g_CurCharNum > g_StringLen)      
        return true;
                                             
    if (g_Boggle[y][x] == CurChar)
    {
        if (g_StringLen == 1){
            // 기저사례 3 문자를 찾았는데 문자열의 
            // 길이가 1이면 곧 찾는 문자열이므로 true
            return true;
        }
 
        // 문자를 찾았으면 문자인덱스를 1증가
        ++g_CurCharNum;   
 
        // 현 인덱스를 중심으로 다음 문자를 8방향 검사
        for (int i = 0; i < 8; i++)
        {
            // 모두 찾으면 true
            if (f(
                (y + g_ArrY[i]), // y좌표
                (x + g_ArrX[i]), // x좌표
                g_WordsArr[g_CurWordNum][g_CurCharNum])
                )
            {
                return true;       
            }
        }
        // 문자를 못찾았으면 문자인덱스 1감소
        --g_CurCharNum;      
    }
    // 현 인덱스의 문자가 찾는 문자가 아니면 false
    return false;       
}
 
 
int main()
{
    // 테스트 케이스
    int testCase = 0;
    int stringCount = 0;
    int temp = 0;
    for (int i = 0; i < BOGGLE_MAX; i++)
    {
        g_Boggle[i] = new char[BOGGLE_MAX + 1]();
    }
    for (int i = 0; i < WORD_MAX; i++)
    {
        g_WordsArr[i] = new char[WORD_MAX + 1]();
    }
 
    scanf("%d", &testCase);
    while (testCase--){
        g_CurWordNum = 0;
        
        // 보글게임판 5 x 5 입력
        for (int i = 0; i < BOGGLE_MAX; i++)     
        {
            scanf("%s", g_Boggle[i]);
        }
 
        // 확인하려는 문자열 갯수 입력
        scanf("%d", &stringCount);
        temp = stringCount;
        // 확인하려는 문자열 입력  ENTER 구분
        for (int i = 0; i < stringCount; i++)
           {
            scanf("%s", g_WordsArr[i]);
        }
 
        while (stringCount--){
            bool isYes = false;
            // 현재 검사하려고 하는 문자열의 길이 저장
            g_StringLen = (int)strlen((const char*)g_WordsArr[g_CurWordNum]);
            // g_CurCharNum = 현재 검사하려고하는 문자 인덱스 예) ABCDE에서 C 면 2    
            g_CurCharNum = 0;               
 
            for (int y = 0; y < BOGGLE_MAX; y++)
            {
                for (int x = 0; x < BOGGLE_MAX; x++)
                {
                    // y, x인덱스와 찾으려는 문자열의 문자를 f에 넘김
                    // 있으면 YES
                    if (
                        f(y,
                          x, 
                          g_WordsArr[g_CurWordNum][g_CurCharNum]))     
                    {
                        printf("%s YES\n", g_WordsArr[g_CurWordNum++]);
                        isYes = true;      // 루프를 빠져나간다.
                        break;              // 루프를 빠져나간다.
                    }
                }
                if (isYes)              // 루프를 빠져나간다..
                break;                      // 루프를 빠져나간다..
            }
            
            // 4, 4까지 돌았는데 없으면 NO    
            if (!isYes)     
            {
                printf("%s NO\n", g_WordsArr[g_CurWordNum++]);
            }
        }
    }
    
    // 메모리 해제
    for (int i = 0; i < BOGGLE_MAX; i++)        
    {
        delete []g_Boggle[i];
        g_Boggle[i] = NULL;
    }
    for (int i = 0; i < WORD_MAX; i++)
    {
        delete[]g_WordsArr[i];
        g_WordsArr[i] = NULL;
    }
    return 0;
}
cs

결과

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
1
KKKKS
KEEEK
KEYEK
KEEEK
KKKKK
10
YES
YESYES
SYESEY
YESSEY
SYESKSYEY
YESKK
SYESKKY
YESKEY
YESEEY
YESEEEEEEEY
YES YES
YESYES NO
SYESEY NO
YESSEY NO
SYESKSYEY NO
YESKK YES
SYESKKY NO
YESKEY YES
YESEEY YES
YESEEEEEEEY YES
cs


위 방법으로 구하면 최대 

50(최대 테스트 케이스) * 10(문자열의 개수)  * 8^10 (8방향으로 검사하는 것을 글자수만큼 반복 최대 10)

대략 5000억 정도..어마어마하다. 당연 시간초과

이것을 어떻게 줄일 수 있을까.

'All > Algorithm' 카테고리의 다른 글

BOGGLEGAME_알고리즘_3  (0) 2015.12.28
BOGGLEGAME_알고리즘_2  (0) 2015.12.28
BOGGLEGAME_문제  (0) 2015.12.28
ZEROONE_알고리즘  (0) 2015.12.28
ZEROONE_문제  (0) 2015.12.28

이번에 푼 문제는 BOGGLEGAME 이다.

아래와 같다.


문제

 

보글(Boggle) 게임은 그림 (a)와 같은 5x5 크기의 알파벳 격자인 
게임판의 한 글자에서 시작해서 펜을 움직이면서 만나는 글자를 그 순서대로 나열하여 만들어지는 영어 단어를 찾아내는 게임입니다. 펜은 상하좌우, 혹은 대각선으로 인접한 칸으로 이동할 수 있으며 글자를 건너뛸 수는 없습니다. 지나간 글자를 다시 지나가는 것은 가능하지만, 펜을 이동하지않고 같은 글자를 여러번 쓸 수는 없습니다.

예를 들어 그림의 (b), (c), (d)는 각각 (a)의 격자에서 PRETTY, GIRL, REPEAT을 찾아낸 결과를 보여줍니다.

보글 게임판과 알고 있는 단어들의 목록이 주어질 때, 보글 게임판에서 각 단어를 찾을 수 있는지 여부를 출력하는 프로그램을 작성하세요.

 

입력

 

입력의 첫 줄에는 테스트 케이스의 수 C(C <= 50)가 주어집니다. 각 테스트 케이스의 첫 줄에는 각 5줄에 5글자로 보글 게임판이 주어집니다. 게임판의 모든 칸은 알파벳 대문자입니다.
그 다음 줄에는 우리가 알고 있는 단어의 수 N(1 <= N <= 10)이 주어집니다. 그 후 N줄에는 한 줄에 하나씩 우리가 알고 있는 단어들이 주어집니다. 각 단어는 알파벳 대문자 1글자 이상 10글자 이하로 구성됩니다.

 

출력

 

각 테스트 케이스마다 N줄을 출력합니다. 각 줄에는 알고 있는 단어를 입력에 주어진 순서대로 출력하고, 해당 단어를 찾을 수 있을 경우 YES, 아닐 경우 NO를 출력합니다.

 

예제 입력

1
URLPM
XPRET
GIAET
XTNZY
XOQRS
6
PRETTY
GIRL
REPEAT
KARA
PANDORA
GIAZAPX

예제 출력

PRETTY YES
GIRL YES
REPEAT YES
KARA NO
PANDORA NO
GIAZAPX YES


요약하면

1. 5 x 5의 배열에 문자열 입력 

2. 그후 길이가 10이하인 문자열 N개 입력

3. 5 x 5의 배열의 한 원소에서 시작해서 인접하는 원소들을 연결하여 문자열이 존재하는지 확인 존재하면 YES 아니면 NO 

4. 연결할때 사용했던 문자를 다시 사용할 수 는 있지만 한 문자를 연속해서 계속 사용할 수는 없다.

조건 테스트케이스는 50이며 10000ms안에 수행되어야한다. 

*문제 출저 알고스팟

'All > Algorithm' 카테고리의 다른 글

BOGGLEGAME_알고리즘_3  (0) 2015.12.28
BOGGLEGAME_알고리즘_2  (0) 2015.12.28
BOGGLEGAME_알고리즘_1  (0) 2015.12.28
ZEROONE_알고리즘  (0) 2015.12.28
ZEROONE_문제  (0) 2015.12.28

1. 무식하게 풀기


생각

1단계. 먼저 0, 1로 이루어진 수열을 배열에 입력받는다.

2단계. 두개의 인덱스A, B를 입력받는다.

3단계. 함수 bool f(int A, int B)를 호출

함수 내용 

- 배열의 A번째부터 B까지 순차적으로 비교

- 비교 중 A번째 인덱스에 들어있는 값과 다르면 false 리턴


코드

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
#include <iostream>
// 백만
static const int MAX = 1000000;
char g_ZeroOneArr[MAX + 1= {0, };
bool f(int indexA, int indexB);
 
int main(void)
{
    // 입력되는 두 수
    int indexA, indexB = 0;
    // 테스트 케이스
    int testCase = 0;
    scanf("%s", g_ZeroOneArr);
    scanf("%d", &testCase);
    
    while(testCase--){
        // 두 수 입력
        scanf("%d %d", &indexA, &indexB);
 
        // 오름차순 정렬
        if(indexA > indexB)
        {
            int temp = indexA;
            indexA = indexB;
            indexB = temp;
        }
        
        // (모두 1 or 모두 0) == YES
        if(f(indexA, indexB))
            printf("Yes\n");
        else
            printf("No\n");
    }
}
// 함수 구현
// 인덱스 A ~ B까지 반복 하며 중간에 값이 변하면 FALSE
bool f(int indexA, int indexB)
{
    for(int i = indexA; i <= indexB; i++)
    {
        if(g_ZeroOneArr[i] != g_ZeroOneArr[indexA])
        {
            return false;
        }
    }
    return true;
}
 
 
cs
 

출력

1
2
3
4
5
6
7
8
9
10
11
12
13
1111100000
 
5
1 0
Yes
1 1
Yes
4 5
No
5 4
No
0 9
No
cs


위와같이 출력되는것을 알수 있다. 

하지만 위의 코드를 문제 풀이 사이트에 제출하면 [TimeOut] 이 되어버린다.


좀더 빠른 코드를 짜야한다.

먼저 위의 코드는 아래와 같은 최악의 경우


0000000....1(N = 100만)

indexA = 0, indexB = 999999

테스트 케이스 10만


100만 * 10만 의 for문을 반복한다.


2. 배열에 기록하기


생각

1단계. 먼저 0, 1로 이루어진 수열을 배열에 입력받는다.

2단계. 배열을 0 ~ N 까지 반복하면서 i값을 기록한다. (i는 0부터 시작)

          - if( arr[N] != arr[N -1] ) 라면 i 값을 1더하여 기록

3단계. 함수 bool f(int A, int B)를 호출

함수 내용 

- 배열의 A번째 원소와 B번째 원소의 값이 서로 다르면 false 같으면 true 반환


코드


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
// ZEROONE_2
#include <iostream>
 
// 백만
static const int MAX = 1000000;
// 수열 배열
char g_ZeroOneArr[MAX + 1= {0, };
// 기록 배열
int g_CheckFlagArr[MAX + 1= {0, };
bool f(int indexA, int indexB);
 
int main(void)
{
    // 입력되는 두 수
    int indexA, indexB = 0;
    // 테스트 케이스
    int testCase = 0;
    // 수열의 길이
    unsigned long stringLength = 0;
    unsigned int checkFlag = 0;
    
    scanf("%s", g_ZeroOneArr);
    scanf("%d", &testCase);
    stringLength = strlen(g_ZeroOneArr);
    
    // 체크 플래그 설정
    // i번째 요소와 i-1번째 요소가 서로 다르면 check + 1
    for(int i = 1 ;i < stringLength; i++)
    {
        if(g_ZeroOneArr[i-1!= g_ZeroOneArr[i])
            checkFlag++;
        g_CheckFlagArr[i] = checkFlag;
    }
    
    while(testCase--){
        // 두 수 입력
        scanf("%d %d", &indexA, &indexB);
        
        // (모두 1 or 모두 0) == YES
        if(f(indexA, indexB))
            printf("Yes\n");
        else
            printf("No\n");
    }
}
cs


출력

1
2
3
4
5
6
7
8
9
10
11
12
1010101100
5
1 2
No
2 1
No
1 1 
Yes
2 4
No
4 5
No
cs


딱히 어려운 부분은 없으므로 설명은 생략하고 for문 횟수를 보면 

처음에 최대 100만번을 반복하고 그후에는 반복이 없는 것을 알수 있다.

즉 100만 + 10만 최대 110만 번 반복,  이전의 알고리즘보다 매우 빠른 속도를 낼 수 있다는것을 알 수 있다. 

문제풀이 사이트에 제출하니 (실행시간 241ms) 정답을 받을 수 있었다. 

'All > Algorithm' 카테고리의 다른 글

BOGGLEGAME_알고리즘_3  (0) 2015.12.28
BOGGLEGAME_알고리즘_2  (0) 2015.12.28
BOGGLEGAME_알고리즘_1  (0) 2015.12.28
BOGGLEGAME_문제  (0) 2015.12.28
ZEROONE_문제  (0) 2015.12.28

이번에 푼 알고리즘문제는 ZEROONE이라는 문제이다.

먼저 문제를 보면 아래와 같다.



문제

 

0과 1로 구성된 수열이 있다. 수열의 길이가 N이라 하고, 각각의 수열의 원소마다 순서대로 번호를 매길 경우 첫 번째 숫자는 0번이 되고 두 번째 숫자는 1번, 그리고 마지막 숫자는 N-1이 된다. 임의적으로 0이상 N-1이하의 2개의 숫자 i,j를 잡고 i번째부터 j번째 까지의 숫자 중에서의 최대값과 최소값을 찾아서 두 값이 일치하는지 알아보고자 한다.

 

입력

 

첫 번째 줄에는 최대 길이 1,000,000의 수열이 들어온다. 수열의 사이에는 빈칸이 없다. 그 다음 줄에는 질문의 개수를 뜻하는 정수 N(N<=100,000)이 입력된다. 그 다음줄부터 해당구간 i,j를 의미하는 2개의 숫자가 N개의 줄로 입력된다.

 

출력

 

각각의 질문의 순서대로 해당구간 i,j의 최대값과 최소값이 같을 경우 Yes를, 그렇지 않을 경우는 No를 출력한다.

 

예제 입력

0000011111
3
0 5
4 2
5 9

예제 출력

No
Yes
Yes

노트

 

0,5 : 000001 -> 최대값 : 1, 최소값 : 0
4,2 : 000 -> 최대값 : 0, 최소값 : 0
5,9 : 11111 -> 최대값 : 1, 최소값 : 1


요약하면

1. 0또는 1로 이루어진 수열 (0101010101... 최대 100만 ) 이 입력됨

2. 각각의 원소는 0부터 차례로 인덱스를 가짐 

3. 임의의 2개의 인덱스를 입력 받음

4. 두 인덱스사이의 값이 모두 0또는 모두 1이면 Yes출력 아니면 No출력

최대 10만번의 테스트를 2000ms (2초) 안에 수행해야한다.

 *문제 출저 알고스팟


'All > Algorithm' 카테고리의 다른 글

BOGGLEGAME_알고리즘_3  (0) 2015.12.28
BOGGLEGAME_알고리즘_2  (0) 2015.12.28
BOGGLEGAME_알고리즘_1  (0) 2015.12.28
BOGGLEGAME_문제  (0) 2015.12.28
ZEROONE_알고리즘  (0) 2015.12.28

코드 하이라이터 기능을 위해 티스토리로 옮겼다.

네이버 글을 이쪽으로 옮겨야 겠다.

또 열심히 글써야지 

아 그리고 사소한 것이라도 쓸 예정이다.

자꾸 큰 내용만 쓰려하니까 더 안쓰게 되는 것 같다.

'All > ETC' 카테고리의 다른 글

국토종주  (0) 2017.05.10
유용한 사이트  (0) 2016.11.28
훈련소 (2016. 01. 21 ~ 2016. 2. 18)  (2) 2016.01.19

+ Recent posts