근래 출제된 삼성 문제의 특징 중 하나는, 대단한 알고리즘을 요구하는 것보다도

 

독해력을 많이 보는 것이 아닐까 한다.

 

아기상어는 std::priority_queue가 사용가능하다면 금방 풀수 있고

나무재테크는 알고리즘이랄게 아예 없다.

 

다만 둘다 문장 하나하나에 조건이 조그마하게 숨어있어서 처음 문제 파악할 떄

제대로 읽지않는다면 낭패를 보거나 풀이 자체가 불가능하다.

 

예를 들어, 나무재테크 문제는 이동방향이 대각선 포함 8방향이다.

처음에 문제를 제대로 안읽으면 4방향이라 어림짐작하고 덤비기 쉽상이다.

 

일단 돌아와서 문제의 포인트는 정렬, 그리고 문제를 봄,여름,가을,겨울에서 봄+여름,가을,겨울 로 나눠 생각하는거다.

또 최초영양분이 모든칸에서 5라는 사실을 잊어선 안된다.

 

죽음과 삶이란 상태가 있는것 처럼 보이지만 그렇지 않다.

사실상 봄에 나이먹는과정+양분 부족해서 시체로 만드는과정을 합친게 한 칸에서 한번에 이루어지기 떄문이다.

자료구조는 vector들의 2차원배열 vector<int> land[11][11]->  land[r][c]->(r,c)는 나무 나이 벡터로 충분해보인다.

 

그러므로 봄이 시작하기전에

1. 나이순으로 정렬을 하고

2. 나이를 먹이면서 영양을 빼고(나이먹은 나무는 따로 aging벡터에 저장한다)

3. 영양이 부족하면 나이/2를 시체로 만든다.

4. 백업해둔 aging벡터로 기존 나이를  덮는다.

 

가을 겨울은 너무 쉬워서 패스. 

 

시간초과가 많이난다는 평이 있는데, 개인적으론 시뮬레이션 문제는 정말 특이한 경우가 아니면  C++로 푸는게 좋다고 본다.

Python list 만큼은 아니지만 STL만 해도 알고리즘구현하는데 충분한 유연성을 제공해줄수있고,

로직이 다소 개판이어도 빠른 성능으로 커버할 수 있다.

 

 

 

 

 

 

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> land[11][11];
int F[11][11];
int A[11][11];
int N, M, K;
int dr[] = { -1,    -1,    -1,    0,    0,    1,    1,    1 };
int dc[] = { -1,     0,     1,    1,    -1,    -1,    0,    1 };
 
void first_half()
{
    for (int r = 1; r <= N; r++)
    {
        for (int c = 1; c <= N; c++)
        {
            vector<int> aging;
            sort(land[r][c].begin(), land[r][c].end());
            int dead = 0;
            for (size_t i = 0; i < land[r][c].size(); i++)
            {
                if (land[r][c][i] <= F[r][c])
                {
                    F[r][c] -= land[r][c][i];
                    aging.push_back(land[r][c][i] + 1);
                }
                else
                {
                    dead += land[r][c][i] / 2;
                }
            }
            // 산 나무
            land[r][c].clear();
            for (size_t i = 0; i < aging.size(); i++)
            {
                land[r][c].push_back(aging[i]);
            }
            F[r][c] += dead;
        }
    }
}
 
void second_half()
{
    for (int r = 1; r <= N; r++)
    {
        for (int c = 1; c <= N; c++)
        {
            for (int i = 0; i < land[r][c].size(); i++)
            {
                if (land[r][c][i] % 5continue;
                int nr, nc;
                for (int d = 0; d < 8; d++)
                {
                    nr = r + dr[d];
                    nc = c + dc[d];
                    if (nr > 0 && nr <= N && nc > 0 && nc <= N)
                    {
                        land[nr][nc].push_back(1);
                    }
                }
            }
        }
    }
    for (int r = 1; r <= N; r++)
    {
        for (int c = 1; c <= N; c++)
        {
            F[r][c] += A[r][c];
        }
    }
}
int main(void)
{
    cin >> N >> M >> K;
    for (int r = 1; r <= N; r++)
        for (int c = 1; c <= N; c++)
        {
            cin >> A[r][c];
            F[r][c] = 5;
        }
    int r, c, a;
    for (int i = 1; i <= M; i++)
    {
        cin >> r >> c >> a;
        land[r][c].push_back(a);
    }
    for (int k = 0; k < K; k++)
    {
        first_half();
        second_half();
    }
    int trees = 0;
    for (int r = 1; r <= N; r++)
        for (int c = 1; c <= N; c++)
            trees += land[r][c].size();
    cout << trees << '\n';
    return 0;
}
cs

 

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

7576번 : 토마토  (0) 2019.07.15
1212번 : 8진수 2진수  (0) 2019.07.15
9012번 : 괄호  (0) 2019.07.15
STL을 이용한 자료구조  (0) 2019.07.15
문제풀이 계획  (0) 2019.07.15

안익은 토마토는 대충 버리지 왜 이런 시뮬레이션을...

 

원래 예전에 풀었던 문제들 중에 오답률 높은 것, 기억에 남는 것 위주로 포스팅하고 요즘 풀고있는 문제들을 올리려 하였으나

이건 풀다가 승질이 뻗쳐서 먼저 정리한다.

 

익은 토마토(1)은 주변 4방향으로 전파가 되고 안익은 0을 1로 바꿀 수 있다.

그리고 -1은 비어있는 토마토 이기 때문에 미로에서의 벽과 같은 역할을 한다.

 

다시말해 그냥 미로찾기 문제고, "모든 곳이 다 익었는지"는 모든 미로를 전부 탐험했는지랑 같다.

 

다음과 같은 과정을 거쳐야한다.

 

1. 모든 위치를 방문해야하고(방문해야 토마토가 익은 거니까)

2. 방문하고 났으면 얼마만에 방문한건지(며칠만에 익은건지 확인하기 위해서)

3. 가장 마지막에 방문한 노드의 방문 순서가 계산가능한 최소 시간이다.

 

즉 BFS를 이용하여 최단 경로를 계산하는 문제라고 생각했다만...

낮은 정답률에서 알 수 있듯이 문제는 그게 아니다.

 

일단 방문 할 수 없는 위치가 존재 할 수도있다.

 

전부 익히는 것이 불가능 한 경우


위와 같은 경우 외곽의 토마토는 우상단의 토마토를 통해 다 익을 수 있지만

좌상단의 토마토는 가까운 익은 토마토가 위치 할 수 없어 모든 토마토가 익지 않게된다.

 

.... 정도면 쉬운 문제였을 거고,

 

해결해야 하는 경우가 더 통수의 통수의 통수가 있다.

 

시작 위치가 여러 개인 예제

시작 위치가 여러개인 경우인데,

map상에서 익은 토마토가 map[0][0]과 map[3][5]에 있으니

map[1][0]과 map[3][4] 는 둘다 1이어야 하지만 섣불리 탐색을 시작하면 둘 중 한개는 1이아니라 10이 되어 버린다.

이런 반례가 있을 거라곤 예제에서 주지 않았더라면 상상도 못 했을거다. 

 

말로는 양쪽에서 동시에 출발하면된다고 하지만 어떻게 할지는 생각해내는데 꽤 오랜 시간이 걸렸다.

답은 의외로 간단했는데, 그냥 1(익은 토마토)의 위치를 BFS 돌리기전에 전부 큐에다가 넣어 놓는 것이었다.

그럼 BFS가 운영하는 큐는 아주 손쉽게 양쪽의 시작위치를 번갈아가면서 큐에다가 값을 넣고 탐색하기 때문에 쉽게 해결이 가능했다.

이거 생각 해내는데 한시간이 넘게 걸렸다.

 

좀더 문제를 바라보는 눈을 키워야겠다.

 

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
#include <iostream>
#include <queue>
#include <cstring>
 
using namespace std;
 
struct point
{
    int y;
    int x;
};
 
int N, M;
int dx[4= {-1100};
int dy[4= {00-11};
 
int visited[1000][1000];
queue<point> q;
point last;
 
void tomato();
 
int cnt = 0;
int main(int argc, char *argv[])
{
    cin>>M>>N;
 
    int t;
    for (int i=0; i<N; i++)
    {
        for (int j=0; j<M; j++)
        {
            cin>>t;
            if(t == 1)
            {
                visited[i][j] = 1;
                q.push({i, j});
            }
            if(t == -1)
                visited[i][j] = -1;
//            map[i][j] = t;
        }
    }
    
    if (q.empty())
        cout<<"-1\n";
    else
    {
        tomato();
        
        bool ismatured = true;
        for (int i=0; i<N; i++)
        {
            for (int j=0; j<M; j++)
            {
                if(visited[i][j] == 0)
                {
                    ismatured = false;
                    break;
                }
            }
            if(!ismatured)
                break;
        }
 
        if(ismatured)
            cout<<visited[last.y][last.x]-1<<"\n";
        else
            cout<<"-1\n";
    }
 
    return 0;
}
 
void tomato()
{
    if (q.empty())
        return;
    point p = q.front();
    q.pop();
    last = p;
 
    for (int i=0; i<4; i++)
    {
        if((visited[p.y+dy[i]][p.x+dx[i]] == 0&& \
           !(p.x+dx[i] < 0 || p.x+dx[i]>=|| p.y+dy[i] < 0 || p.y+dy[i]>=N))
        {
            q.push({p.y+dy[i], p.x+dx[i]});
            visited[p.y+dy[i]][p.x+dx[i]] = visited[p.y][p.x] + 1;
        }
    }
    
    tomato();
}
 
cs

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

16235번 : 나무 재테크  (0) 2019.10.17
1212번 : 8진수 2진수  (0) 2019.07.15
9012번 : 괄호  (0) 2019.07.15
STL을 이용한 자료구조  (0) 2019.07.15
문제풀이 계획  (0) 2019.07.15

이유는 알 수 없지만 진법 변환하는 쉬운 문제임에도 정답율이 매우 낮다.

통계를 보니 시간초과로 틀린 분들이 많은 걸 알 수있었다.

 

그 말은 즉 통상적인 방법인,

1. 나눈다.

2. 나머지를 모은다.

3. 뒤집는다.

로는 어려울 수 있다는 뜻이다.

 

그래서 조금 다르게 풀었다.

8진수를 2진수로 각 자리를 변환하면 0~7까지 000, 001, 010, 011, 100, 101, 111로 표현 할 수 있다.

 

저걸 배열에 저장해서 입력된 문자열의 각 자리를 그대로 인덱스로 사용해서 꺼내오면 된다.

 

유사 코드로 작성하면, 다음과 같다.

=========================

oct2bin[] = {000, 001, 010, 011, 100, 101, 111}

cin>>oct

 

// 앞자리는 1로만 시작해야함

if oct[0] ==3 or 2 then print(oct2bin[oct[0]-'0'][1]) print(oct2bin[oct[0]-'0'][2])

if oct[1] == 1 then print(oct2bin[oct[0]-'0'][2])

 

loop : oct i 1->len

start

print(oct2bin[oct[i]-'0'])

end

print("\n")

=========================

 

단, C++기준으로 매번 cout을 하면 퍼포먼스가 떨어지므로 stringstream에 모아서 나중에 한번에 출력한다.

cout 매번 하기 vs stringstream으로 한번에 하기

두 가지 모두 해봤는데, 매번 cout을 하는 것보다 stringstream으로 한번에 출력하는 것은 메모리를 1.5배정도 더 썼다.

하지만 속도는 1/1.5 배였다.

 

끝으로 문제에 함정 카드가 하나 있긴한데, 그건 소스코드 보시면서 확인해보시거나, 직접 한번 생각 해보시는 것도 좋을 것 같다.

그것 때매 한번 틀리고 고민좀 했었다.

 

 
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
#include <iostream>
#include <string>
#include <sstream>
 
using namespace std;
 
int main(int argc, char *argv[])
{
    string oct = "";
    stringstream bin;
    char oct2bin[8][4= {"000""001","010","011","100","101","110","111"};
 
    cin>>oct;
    if (oct == "0")
    {
        cout<<"0\n";
        return 0;
    }
    
    
    if ((oct[0]-'0' == 3)  || (oct[0]-'0' == 2))
        bin<<oct2bin[oct[0]-'0'][1]<<oct2bin[oct[0]-'0'][2];
    else if (oct[0]-'0' == 1)
        bin<<oct2bin[oct[0]-'0'][2];
    else
        bin<<oct2bin[oct[0]-'0'];
    
    for (int i=1; i<oct.length(); i++)
    {
        bin<<oct2bin[oct[i]-'0'];
    }
    
    cout<<bin.str()<<"\n";
    
    return 0;
}
 
cs

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

16235번 : 나무 재테크  (0) 2019.10.17
7576번 : 토마토  (0) 2019.07.15
9012번 : 괄호  (0) 2019.07.15
STL을 이용한 자료구조  (0) 2019.07.15
문제풀이 계획  (0) 2019.07.15

이 문제는 사실 예전에 본적이 있다.

먼 과거긴 하지만 수많은 노가다를 통해 일종의 인식기를 만들어서 풀었고 심지어 답도 맞췄다.

요즘 말로하면 "어케 맞췄노" 정도 되겠다.

 

각설하고 문제를 분석하면, 쉽게 말해 Stack을 통한 인식기를 만들라는 것이다.

원리는 간단하다.  "("가 나오면 push하고 ")"가 나오면 pop한다.

몇 번째 "("가 ")"와 짝인진 사실 알기 힘들다. 하지만 명백한 사실은, 스택에 "(" 가 남아있다면 ")"이 부족하단 것이다.

 

단, 낮은 정답률에서 알 수 있다시피 그게 다가 아니다. 조심해야할 예외가 있다.

 

코드는 아래와 같다.

 

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
#include <iostream>
#include <stack>
#include <string>
 
using namespace std;
 
int main(int argc, char *argv[])
{
    int T;
    cin>>T;
    
    stack<char> stk;
    string op;
    bool vps = true;
 
    for (int i=0; i<T; i++)
    {
        cin>>op;
        vps = true;
        for (int j=0; j<op.length(); j++) {
            if(op[j] == '(')
                stk.push(op[j]);
            else
            {
                if(!stk.empty())
                {
                    stk.pop();
                }
                else
                    vps = false;
            }
        }
        if(stk.empty() && vps) cout<<"YES"<<endl;
        else            cout<<"NO"<<endl;
        
        while(!stk.empty()) stk.pop();
    }
    
    return 0;
}
cs

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

16235번 : 나무 재테크  (0) 2019.10.17
7576번 : 토마토  (0) 2019.07.15
1212번 : 8진수 2진수  (0) 2019.07.15
STL을 이용한 자료구조  (0) 2019.07.15
문제풀이 계획  (0) 2019.07.15

자료구조를 매번 직접 구현해서 푸는 건 거의 불가능에 가깝다.

C style로 풀더라도 STL을 사용하면 좀더 빠른 구현이 가능하니까 익숙해지도록 하자.

 

Stack : 10828번 (http://boj.kr/d9375b2a95744c15836b94b588c425cc)

Queue : 10845번 (http://boj.kr/9412f140024348dca6c335e71c60a8a9)

Deque : 10866번 (http://boj.kr/c196f255fb8046d78444fcf52816a9e5)

Priority queue : 11279번 (http://boj.kr/26fffbf3bd8647ef82c268b593c11f25)

 

자료구조를 한번에 다루다 보니까 소스코드를 직접 올릴 수 없어 코드로 대체한다.

문제에서 수행해야 할 커맨드 (10828번)

대체로 주어진 구현해야하는 커맨드는 위와 같다. 소소한 차이는 있지만, 크게 벗어 나지 않는다.

네 자료구조 모두 비어있는 상태에서 pop()을 시도하거나 값을 가져오려고하면 메모리 접근 관련된 런타임 에러가 난다는 것을 감안해서 프로그램을 작성 해야한다. 문제에서 pop()에 관한 조항이 있으니 실수로라도 놓지지 말고 반드시 확인하도록 하자.

 

또한, cin, cout이 시간을 많이 쓰므로, Priority queue에선 시간 초과가 난다는 점을 조심해야 한다.

 

split()을 대신한 stringstream

Java가 아니라 C++로 문제를 푸는 사람들은 입력시 " "(공백문자)를 어떻게 처리 해야할지 난감할 때가 있다.

"push_front 1" 같은 입력은 띄어쓰기 때문에 cin으로는 원하는 입력을 얻을 수 없다. 

 

std::getline()을 이용하여 입력받고, 입력받은 op를 stringstream에 넣어 스트림으로서 하나씩 꺼내 쓸 수 있어,

사실상 split()을 한 것과 비슷한 효과를 얻을 수 있다.

 

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

16235번 : 나무 재테크  (0) 2019.10.17
7576번 : 토마토  (0) 2019.07.15
1212번 : 8진수 2진수  (0) 2019.07.15
9012번 : 괄호  (0) 2019.07.15
문제풀이 계획  (0) 2019.07.15

상반기에 코딩테스트를 보러 역삼에 갔었지만

 

흠씬 두들겨 맞고 돌아왔다.

 

서류는 자신있으니, 실력을 길러 합격하도록 하자!

백준 : 단계별로 풀어보기 화면

우선 삼성에서 광탈한 후 나의 현실을 먼저 파악해보니 기본적으로 내 실력이 형편 없단 걸 깨달았다.

이론이야 알지만, 시간 복잡도를 계산하거나 문제 해결을 위한 계획하는 게 엉망이었다.

손이 펜보다 프로젝트 만들기에 먼저가니  문제가 풀릴리가 있나.

 

백준(https://www.acmicpc.net/step)에서 우선 구현 위주의 문제를 먼저 풀어보고

 

자료구조, 시뮬레이션, 동적계획법, 브루트포스. 그래프 위주로 문제를 풀 것 이다. 이 일을 7월 중에 마칠 수 있도록 노력해야겠다.

이 일을 7월 중에 마치고, 8월 부턴 SWEA(https://www.swexpertacademy.com)에서 문제를 풀며 삼성 특유의 스토리텔링에 익숙해지도록 할 것이다.

 

또한 고생해서 풀었거나 인상이 깊은 문제들은 이곳에 올리어 정리할 생각이다.

 

사실 시작은 7월 첫째주에 했는데, 블로그에 강해지는 모습을 기록해야겠단 생각이 들어서 뒤늦게 글로서 정리한다.

 

'컴퓨터과학 > 알고리즘 문제풀기' 카테고리의 다른 글

16235번 : 나무 재테크  (0) 2019.10.17
7576번 : 토마토  (0) 2019.07.15
1212번 : 8진수 2진수  (0) 2019.07.15
9012번 : 괄호  (0) 2019.07.15
STL을 이용한 자료구조  (0) 2019.07.15

+ Recent posts