본문 바로가기

알고리즘/BOJ

15684번

15684번 -사다리 조작


이번 상반기에 대기업 알고리즘 문제로 나왔던 문제.


막상 가서 실전에서 문제를 풀 때에는 배열을 더 크게 잡아서 약간 미로탐색처럼 문제를 풀었었다. 


하지만 지금 다시 보면서 생각해보니, 각 점들을 노드라고 생각하여 방향 그래프를 완성하면 문제가 쉬워진다.


근데 이 문제에서 계속 헷갈렸던게 입력값이었다.. N,M,H 가 주어지는데 나는 평상시에 N을 세로, M을 가로로 놓고 문제를 많이 풀다보니 헷


갈려서 그냥 변수를 바꿔버렸다. X축은 X로 Y축은 Y로 바꿔서 문제를 풀었다.


그리고 좌표값들을 노드 번호로 바꿔서 문제를 풀었다. 즉 세로가 3, 가로가 4인 사다리로 보았을 때, (1,1)은 1번 노드로, (1,2)는 2번 노드로, 


(1,3)은 3번 노드로 이런식으로 좌표를 노드 번호로 바꾸어서 문제를 풀었다. x좌표,y좌표가 주어졌을 때 (x-1)*가로+y 를 이용하면 노드 번호


를 순서대로 구할 수 있게 된다.


그리고 맨 처음에 아래 방향으로 노드들을 모두 연결해준다. 아래에서 위로는 올라올 수 없기 때문에 위에서 아래방향으로 연결한다. 


이때 맨 마지막 줄을 한 줄 더 추가해서 맨 마지막 노드들도 아래 방향으로 가는 간선이 생기도록 만든다. 그래야 나중에 케이스를 구분할 때 


편하기 때문이다. 이렇게 만들면 모든 노드들은 아래 방향으로 이동할 수 있는 간선이 1개씩 생기고, 이 간선은 vector 의 0번 index에 들어가


게 된다. 그리고 간선을 입력받으면서 양방향으로 연결되도록 만들어준다. 이런식으로 하면 가로 방향 간선은 vector 의 1번 index에 들어간


다. 이렇게 주어진 연결을 모두 마치면 이제 for문을 이용해서 최대 3개까지 간선을 만드는 완전 탐색을 실행한다. (문제에서 4이상은 -1을 출


력하라고 했기 때문에..)


재귀함수를 이용해서 간선을 만들고 정답이 맞는지 find_last() 함수를 이용한다.


시작점에서 가로를 우선으로 움직이면서 방문한 곳은 visited 를 true 로 체크하면서 이동한다. 그러다가 맨 마지막 줄보다 아래로 내려가서 


더 이상 움직일 곳이 없을 때의 값을 시작값과 비교하면 되는데, 두 값을 빼고 가로 길이인 Y로 나누었을 때 나누어 떨어지면 맞는값이 된다.


처음에 시간초과가 발생했는데, go() 함수에서 before 라는 인자를 추가해서 중복되는 값을 없애서 시간내에 통과할 수 있게 되었다.


<정답 코드>


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
#include<iostream>
#include<vector>
using namespace std;
 
typedef struct pos
{
    int x;
    int y;
}pos;
 
int X, M, Y;
bool find_ans = false;
 
// 시작점으로부터 끝점을 찾는 함수
bool find_last(vector<vector<int>> &node, int start)
{
    bool visited[300= { false, };
    int cur = start;
    while (true)
    {
        visited[cur] = true;
        int next;
        if (node[cur].size() == 2)
        {
            next = node[cur][1];
            if (!visited[next])
                cur = next;
            else
                cur = node[cur][0];
        }
        else if(node[cur].size()==1)
        {
            next = node[cur][0];
            cur = next;
        }
        else
        {
            break;
        }
    }
 
    if ((cur - start) % Y == 0)
        return true;
    else
        return false;
 
}
void go(vector<vector<int>> &node, int k,int before)
{
    if (find_ans)
        return;
 
    if (k == 0)
    {
        bool finish = true;
 
        //첫번째 노드들을 하나씩 탐색하며 내려감
        for (int i = 1; i <= Y; i++)
        {
            if (!find_last(node, i))
            {
                finish = false;
                break;
            }
        }
 
        if (finish)
            find_ans = true;
 
 
        return;
    }
 
    // 새로 만드는 간선(가로방향)
    for (int i = before+1; i <= X * Y; i++)
    {
        if (node[i].size() < 2 && i%Y != 0)
        {
            node[i].push_back(i + 1);
            node[i + 1].push_back(i);
            go(node, k - 1,i);
            node[i].pop_back();
            node[i + 1].pop_back();
 
        }
    }
 
 
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    //freopen("input.txt", "r", stdin);
 
    cin >> Y >> M >> X;
 
    vector<vector<int>> node((X+1)*+ 1);
 
    //세로 방향의 노드를 연결
    for (int i = 1; i <= Y * X; i++)
    {
        node[i].push_back(i + Y);
    }
 
    //가로 방향의 노드를 연결
    for (int i = 0; i < M; i++)
    {
        int a, b, to, from;
        cin >> a >> b;
        to = (a - 1)*+ b;
        from = to + 1;
        node[to].push_back(from);
        node[from].push_back(to);
    }
 
    // 0번,1번,2번,3번 완전 탐색
    for (int i = 0; i < 4; i++)
    {
        go(node, i,-1);
 
        if (find_ans) {
            cout << i << endl;
            break;
        }
    }
 
    // 완전 탐색을 해도 정답을 찾을 수 없을 때
    if (!find_ans)
        cout << -1 << endl;
 
 
 
 
    return 0;
}
cs


반응형

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

15658번  (0) 2018.10.07
15663번  (0) 2018.10.04
1938번  (0) 2018.08.30
2665번  (0) 2018.08.30
15649번  (0) 2018.08.06