티스토리 뷰

#문제

https://www.acmicpc.net/problem/5213


#풀이


읽는데 힘들었고(아이언맨에... 닥터후까지 나오는..대서사기...) 굉장히 시간이 많이 걸렸던 문제였습니다.

어디가 틀렸는지 제대로 찾지 못하였다가 결국 반례를 찾게 되었습니다...


구글링을 해보니 저처럼 푸신 분은 거의 없었습니다... 

이걸 좋아해야하는지... 

머리가 나쁜건지... 모르겠습니다... :(


일단, 타일 자체를 받는데 고민을 많이했습니다.

기본 맵과는 다르게 홀수 줄에서는 N열, 짝수 줄에서는 N-1열이기 때문입니다.


저는 홀수줄은 1~2N번째 열을 입력 받았고, 짝수줄은 2~(2N-1)열을 입력 받아 칸마다 값들을 넣었습니다.

또한 두 칸마다 하나의 타일이므로 2개씩 묶어 타일 번호를 지정해 주었습니다.(아래 자세한 그림 참조!)

추가적으로 거리 값도 넣어주었는데, 해당 타일에 접근했었는지 확인을 하는 값입니다.




입력을 받은 후에는 BFS로 갈 수 있는 길을 모두 방문해 주어야 합니다.

이전에도 말했듯이 최소 거리라는 말이 나오게 되면 바로 BFS로 접근 하는 경향이 있어 이번에도 BFS로 풀게 되었습니다.


큐에 넣을때 타일 전부 즉, [1,1], [1,2]를 한 셋트로 넣어주어야 합니다. (코드 -> 생성: 12줄 ,저장: 63)

이를 못찾고 계속 헤매서... 몇시간동안 본듯하네요...


이렇게 해서 갈 수 있는 길을 모두 넣어 주시고, 돌려주시면 됩니다.

이때! 가는 경로도 조사를 해야합니다.

과연 어떻게 알 수 있을까요?(생각을 해보시고 밑 부분을 드래그하여 답을 확인 해봅시다!)


가는 경로를 알기 위해서 새로운 배열을 만들고 그곳에 왔던 길을 등록하면 편하겠죠? :)

예를 들어 가는 길이 1 -> 3 -> 5 라고 한다면, 5에는 3, 3에는 1을 등록하는 방법입니다.

배열은 [0, 0, 1, 0, 3] 이런 식으로 저장이 되어있을 겁니다.


따라서, 새로운 배열을 만들어 그 곳에 왔던 길을 계속해서 저장합니다.(코드 -> 23,24)


그리고 또 하나 놓쳐서는 안되는 조건이 있습니다.

"마지막 줄의 마지막 타일로 이동할 수 없는 경우가 존재할 수 있다. 이 경우에는 번호가 가장 큰 타일로 이동하면 된다." 라는 조건입니다.

즉, 위 그림에서 23번 타일에 도달하지 못하였을 경우 22, 21, 20 조사하여 최대로 멀리 간 경우를 찾아야합니다.


이는 어떻게 찾을 수 있을까요?

바로 큐에 값을 넣었을 때 해당 타일 값이 더 큰지 확인하고 크다면 타일 값을 넣어주면 됩니다. (코드 -> 66)


최대 타일부터 이전에 저장하며 왔던 길을 거꾸로 조사하며 출력하면 끝! (코드 -> findPath 함수)

 

#코드

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
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
 
struct Tile{
    int value;
    int num;
    int dist;
};
Tile map[501][501 * 2];
int path[501 * 501];
int N;
 
int dr[4= {0,0,-1,1};
int dc[4= {-1,1,0,0};
 
vector<int> way;
int last = 1;
 
void findLoad(){
    queue<pair<intint>> q;
    q.push({1,1});
    q.push({1,2});
    map[1][1].dist = 1;
    map[1][2].dist = 1;
    while (!q.empty()) {
        int r = q.front().first;
        int c = q.front().second;
        q.pop();
        for(int i = 0; i < 4; i++){
            int nr = r + dr[i];
            int nc = c + dc[i];
            int col = nr % 2 == 1 ? N : N-1;
            int start = nr % 2 == 1 ? 1 : 2;
            //범위를 벗어났을때 무시
            if(nr < 1 || nr > N || nc < start || nc > (col*2)+(start-1)) continue;
            
            //이미 방문한 곳 무시
            if(map[nr][nc].dist != 0) continue;
 
            //값이 다르면 움직일 수 없다.
            if(map[nr][nc].value != map[r][c].value) continue;
 
            //타일은 무조건 (왼쪽,오른쪽) 거리가 같아야한다.
            //따라서 왼쪽이 같은 타일일때 오른쪽 거리를 왼쪽에 넣어주고,
            //왼쪽을 큐에 넣어준다.
            bool left = false;
            if(map[nr][nc - 1].num == map[nr][nc].num) left = true;
            map[nr][nc].dist = map[r][c].dist + 1;
            q.push({nr,nc});
            //왼쪽이 같은 타일
            if(left){
                map[nr][nc-1].dist = map[nr][nc].dist;
                q.push({nr,nc-1});
            }
            //오른쪽이 같은 타일
            else{
                map[nr][nc+1].dist = map[nr][nc].dist;
                q.push({nr,nc+1});
            }
            //여태까지 지나온 타일들을 알기 위해 이전 타일을 저장해준다.
            path[map[nr][nc].num] = map[r][c].num;
            
            //번호가 큰 타일 찾기
            if(last < map[nr][nc].num) last = map[nr][nc].num;
        }
    }
}
void findPath(){
    //번호가 제일 큰 타일 찾아서 왔던 길 되돌아 가기
    int temp = last;
    way.push_back(temp);
    while(path[temp] != 0){
        way.push_back(path[temp]);
        temp = path[temp];
    }
    cout << way.size() << endl;
    for(int i = (int)way.size()-1; i >= 0; i--){
        cout << way[i] << " ";
    }
    cout << endl;
}
 
int main(){
    cin >> N;
    int cnt = 1;
    for(int i = 1; i <= N; i++){
        int col = i % 2 == 1 ? N : N-1;
        int start = i % 2 == 1 ? 1 : 2;
        for(int j = start; j <= (col*2)+(start-1); j++){
            cin >> map[i][j].value;
            map[i][j].num = (cnt + 1/ 2;
            cnt++;
        }
    }
    findLoad();
    findPath();
    return 0;
}
 
cs


'알고리즘 문제 풀이 > BOJ' 카테고리의 다른 글

[BOJ 2234] 성곽  (0) 2019.02.24
[BOJ 14442] 벽 부수고 이동하기 2  (0) 2019.02.24
[BOJ 15653] 구슬 탈출 4  (0) 2019.02.18
[BOJ 16197] 두 동전  (1) 2019.02.15
[BOJ 3019] 테트리스  (0) 2019.02.14
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
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
글 보관함