삼성 알고리즘 B 형 문제에서는 문자열을 해쉬하는 것이 필수이다. 

 

이것도 두가지 유형이 있는데 , 

 

array 에서 log(1) 시간으로 멤버에 참조하려고 , 숫자로 변환 한 후에 array 사이즈로 나눈 나머지를 택하는 경우이고 

이때에는 bucket 에 충돌이 일어나기 마련이어서 , open adressing 이나 , chaining 기법이 필요하다. 이때 문자열을 

한 번 더 비교하기 때문에 시간이 더 걸린다. 

 

두번째는 숫자로 변환하고 그대로 숫자를 이용하는 것이다. 

 

숫자로 변환했을 때 , 숫자가 array 로 만들기에는 매우 큰 경우라면 숫자를 비교하기 위해서 사용하면 되고

 

숫자가 작다면 , array index 로 접근하여 , 충돌없이 해쉬 테이블에 바로 접근이 가능하다. 추가로 문자열을

비교하지 않아도 되기 때문에 속도가 빠르다. 

 

변환하는 법은 아래 내용 참고 

 

https://blog.joonas.io/143

 

 

초등학교 4학년 딸아이가 수학학원 문제를 내게 물으러 왔다. 딱 봐도 경우의 수가 많아서 손으로는 풀기가 

 

힘들어 보였다.  선생님들도 쉽게 푸는 방법은 없을 것 같다. 혹시 있으시면 알려주세요....

 

자세히 보니 알고리즘으로 풀 수 있는 경우겠구나 싶어서 풀어 본 문제이다. 그래서 

 

포스팅을 한 번 해본다. 다만 몇 분이나 이 글을 읽을지는 미지수이다. ^^

 

6*6 의 정사각형 map 에서 0,0 에서 시작해서 5,5 로 나가는 길을 찾아야 한다. 갔던 곳은 다시 방문하면 안되고 

 

해당하는 행과 열의 방문횟수는 기준값과 꼭 일치 해야 한다. (아래 표에서 첫번째 행과 마지막 열에 표시) 

 

물론 골인 지점과 정사각형의 크기는 변할 수 있다. 

 

1 3 4 5 2 2  
 start            2
            3
            4
            1
            4
          goal  4

 

처음에는 BFS 로 진행을 하려고 했지만 , 길을 만들 때마다  행과 열을 몇 번이나 지나갔는지 확인해서 기준이 되는 값보다 커지면 바로 리턴해야 되는 데,  BFS 로 진행하면 몇 번 지나갔는지 기록해야 되는 변수가 많아야 되고 예측하기 힘들다고 판단해서 DFS 로 진행하기로 했다. DFS 로 진행하면 해당하는 행과 열에 변수 하나씩만 할당이 되면 된다. (calX, calY) DFS 는 stack 과 재귀가 있다. 나는 그중에서 재귀로 구현을 해봤다. 

 

재귀 함수를 호출 하기 전에 행과 열을 방문한 횟수 및 방문 여부를 업데이트 하고 나올 때는 앞에서 업데이트 한 내용을

다시 원복 시켜준다. 이러한 내용은 DFS 관련 문제를 많이 풀다 보면 한번은 적용해보았을 기법이다. 

 

추가적으로 이 문제는 딸 아이 숙제였기 때문에 길을 확인해야 하기 때문에 , 길도 기록해놓았다. 길은 단순한 Queue 로로 구현했고 , 정답일 때에만 , 즉 기준값과 일치 할 때에만 출력하게 만들어 놓았다. 

 

행과 열을 방문한 횟수가 기준값보다 클 때에는 바로 return 하게 했는 데, 이는 지금 생각해보니 가지치기를 한 셈이 되었다. 물론 실제로 문제로 나와서 제한시간에 오버할 가능성도 없지는 않다. ^^.

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

142

143

144

#include <iostream> 

 

using namespace std;

 

#define MAX_LEN 10

#define STACK_LEN 100000 

 

int myMap[MAX_LEN ][MAX_LEN ];

int calX[MAX_LEN];

int calY[MAX_LEN];

int total;

int lenOfRect;

int xLimit[MAX_LEN];

int yLimit[MAX_LEN];

int globalCnt = 0;

struct myRect {

    int x;

    int y;

} myQueue[STACK_LEN];

int front = -1;

 

int gCnt = 0;

int dx[] = { 0,0,1,-1 };

int dy[] = { 1,-1,0,0 };

int canGo(int x, int y)

{

    if (x < 0 || x >= lenOfRect)

        return 0;

    

    if (y < 0 || y >= lenOfRect)

        return 0;

 

    if (myMap[x][y] == 1)

        return 0;

 

    if (calX[x] + 1 > xLimit[x])

        return 0;

    

    if (calY[y] + 1 > yLimit[y])

        return 0;

 

    return 1

}

int canPrint()

{

    for (int i = 0; i < lenOfRect; i++)

    {

        if (calX[i] != xLimit[i] || calY[i] != yLimit[i])

            return 0;

    

    }

    return 1;

}

void recursive(int x, int y)

{

    int tempX;

    int tempY;

    if (x == lenOfRect - 1 && y == 0)

    {

        gCnt++;

        if (canPrint()) {

            cout << x << " bingo " << y <<"횟수: " << gCnt<<endl;

            for (int i = 0; i <= front; i++)

                cout << myQueue[i].x << " " << myQueue[i].y << endl;

 

            cout << endl;

        }

        

        return;

    }    

    

    for (int i = 0; i < 4; i++) {

        tempX = x + dx[i];

        tempY = y + dy[i];

 

        if (canGo(tempX, tempY))

        {

             calX[tempX]++;

             calY[tempY]++;

            

            front++;

            myQueue[front].x = tempX;

            myQueue[front].y = tempY;

 

            myMap[tempX][tempY] = 1;

 

            recursive(tempX, tempY);

            

            myMap[tempX][tempY] = 0;

            calX[tempX]--;

            calY[tempY]--;

            front--;

        }

    }

}

 

void init(int num)

{

    for (int i = 0; i <num; i++)

        for (int j = 0; j < num; j++)

            myMap[i][j] = 0;

 

    for (int i = 0; i < num; i++)

    {

        calX[i] = 0;

        calX[i] = 0;

    }

    

}

 

int main()

{

    freopen("sample_input.txt""r", stdin);

 

    cin >> total;

    

    for (int i = 0; i < total; i++)

    {

        cin >> lenOfRect; 

 

        init(lenOfRect);

 

        for (int j = 0; j < lenOfRect; j++)

            cin >> yLimit[j];

        

        for (int j = 0; j < lenOfRect; j++)

            cin >> xLimit[j];

    

        calX[0]++;

        calY[0]++;

        front++;

        myQueue[front].x = 0;

        myQueue[front].y = 0;

        myMap[0][0= 1;

 

        recursive(00);

 

        calX[0]--;

        calY[0]--;

        front--;

        myMap[0][0= 0;

        // 감소....

    }

}

Colored by Color Scripter

cs

 

 

sample_input.txt

1
6
1 3 4 5 2 2 
2 3 3 1 4 4

 

'알고리즘' 카테고리의 다른 글

문자열을 정수로 해싱하기  (0) 2021.06.13
백준 온라인저지 5052 번 전화번호 목록  (0) 2019.05.12

TRIE 를 비교적 쉽게 풀 수 있었던 문제 

 

TRIE 를 쓰지 않으면 , 전체 스트링을 비교해야 되니까? O(n^2) 의 알고리즘이 

 

TRIE 를 써서  O(n) 의 속도로 줄어들 은 것 같다. 

 

처음에는 add 를 하면서 바로 NO 인 케이스를 발견해내는 방법으로 진행했는 데

 

12345 가 들어오고 123 이 들어오면 괜찮으나 반대로 123 이 들어오고 12345 가 

 

들어오면 구현이 어려워지는 문제점이 있어서 다른 곳에서 본 대로 , 먼저 add 로 

 

전부 저장해 놓은 후에 , 추후에 find 를 해가면서 NO 를 발견하는 구조로 갔다. 

 

#include 

using namespace std;

#define INTEGER_NUM 10
#define MAX_TREE_SIZE 2000000
#define MAX_NUM 10000

struct NODE {
bool isWord;
NODE* children[INTEGER_NUM];
}nodes[MAX_TREE_SIZE];

int nodes_cnt = 0;

NODE* myalloc() {

for (int i = 0; i < INTEGER_NUM; i++) {
nodes[nodes_cnt].children[i] = NULL;
}
nodes[nodes_cnt].isWord = false;
return &nodes[nodes_cnt++];
}

void add(NODE* root, char* str) {
NODE* c = root;

for (int i = 0; str[i]; i++) {

int nextIdx = str[i] - '0';

if (c->children[nextIdx]) {
c = c->children[nextIdx];
}
else {
NODE* newNode = myalloc();
c->children[nextIdx] = newNode;
c = c->children[nextIdx];
}
}
c->isWord = true;
}

int find(NODE* root, char* str) {
NODE* c = root;

for (int i = 0; str[i]; i++) {
if (c->isWord == true)
return 0;

int nextIdx = str[i] - '0';

c = c->children[nextIdx];
}
return 1;
}

void init() {
nodes_cnt = 0;
}

int canAdd() {
int wordCnt;
char inputStr[MAX_NUM][11];
NODE* root = myalloc();

cin >> wordCnt;

for (int i = 0; i < wordCnt; i++)
{
cin >> inputStr[i];
add(root, inputStr[i]);
}
for (int i = 0; i < wordCnt; i++)
{
if (!find(root, inputStr[i]))
return 0;
}
return 1;
}

int main()
{
int total;

cin >> total;

for (int i = 0; i < total; i++)
{
// 초기화 
init();

if (!canAdd())
cout << "NO" << endl;
else
cout << "YES" << endl;
}
}

'알고리즘' 카테고리의 다른 글

문자열을 정수로 해싱하기  (0) 2021.06.13
DFS 로 풀어보는 "길 만들기 퍼즐"  (2) 2019.05.26

+ Recent posts