알고리즘 문제/[백준]

[백준] 20118번: 호반우가 길을 건너간 이유

latter2005 2020. 11. 29. 01:08

경북대학교 고리콘 대회 문제 : www.acmicpc.net/contest/view/545

 

2020 경북대학교 Goricon

사용 가능한 언어 C++17 Java 8 Python 3 C11 PyPy3 C99 C++98 C++11 C++14 Java 8 (OpenJDK) Java 11 C++20 Python 2 PyPy2 C99 (Clang) C++98 (Clang) C++11 (Clang) C++14 (Clang) C11 (Clang) C++17 (Clang) C++20 (Clang) C90 C2x C90 (Clang) C2x (Clang)

www.acmicpc.net

문제 주소 : www.acmicpc.net/problem/20118

 

20118번: 호반우가 길을 건너간 이유

격자의 왼쪽 위가 0, 0 이고 오른쪽 밑이 N-1, M-1 입니다. 경로에는 시작 지점과 끝 지점이 포함되어야 합니다.

www.acmicpc.net

 

문제 확인

 

언뜻 보면 그래프 탐색 혹은 dp 문제처럼 볼 수 있지만 단순한 아이디어 문제입니다.

XOR연산의 특징인 a xor a = 0임을 이용하고 최대 K가 2*(N+M)이며 이를 넘지 않는 길을 찾는 것에 중점을 두면 됩니다. 이를 통해 하나의 방법을 생각할 수 있습니다.

대각선으로 움직이게 되면 가장 빠르게 원점에 가까워 질 수 있으므로 두 가지 스텝으로 나누어 길을 찾습니다

 

풀이

 

  1. 대각선으로 최대한 움직일 수 있을 때 까지 움직인다. -> n, m 중 작은 수에서 2로 나눈 횟수만큼 움직임
  2. n, m의 남은 수를 처리
  3. n,m이 모두 짝수가 아닌 경우 최종 위치가 목적지가 아니므로 한번 더 이동이 필요함

대각선으로 움직인 후 남은 칸을 처리 해야 합니다.

먼저 가로와 세로 중 남은 칸을 2단위로 이동하는 방식으로 처리합니다.

n, m이 모두 남게 되면 아래와 같이 이동하여 마무리를 합니다. n, m 중 한 값이 남게 되면 남은 값을 통하여 목적지까지 이동을 합니다.

모든 경로는 왕복을 하여 xor 조건을 만족시켜 주어야 하기 때문에 답은 다음과 같이 나옵니다.

결과 : 1 2 1 2 3 4 3 4 5 6 5 6 7 8 7 8 9 10 9 10

K는 20이 되고 문제 조건인 2*(n+m)은 14*2 이므로 조건을 만족하게 됩니다.

 

이 방식을 이용하면 n과 m 중 큰 값을 max, 작은 값을 min으로 두면 경로의 길이는 min*2 + (max-min) * 2 + f가 되므로 2(m * n) 보다 작은 값이 나오게 됩니다. 이때 f는 n, m이 모두 짝수인 경우 탐색 종료지점이 목적지이기 때문에 0, 나머지 경우는 목적지까지 움직이는 길을 추가하여 4가 됩니다.

 

코드

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
#include <cstdio>
using namespace std;
void print(int cross, int move_down, int move_right, int t) {//t : 대각선, 가로세로 움직임이 끝난 후 목적지가 아니라면 경로수에 4를 추가로 더함
    printf("%d\n", ((cross + move_down + move_right) << 1+ t);
    for (int i = 0; i < cross; i += 2) {
        printf("%d %d\n%d %d\n", i, i, i + 1, i + 1);
        printf("%d %d\n%d %d\n", i, i, i + 1, i + 1);//대각선 경로 출력
    }
    int cx = cross - 1, cy = cross - 1;
    for (int i = cross; i < cross + move_down; i += 2) {
        printf("%d %d\n%d %d\n", i, cy, i + 1, cy);
        printf("%d %d\n%d %d\n", i, cy, i + 1, cy);//세로로 움직인 경우 출력
    }
    for (int i = cross; i < cross + move_right; i += 2) {
        printf("%d %d\n%d %d\n", cx, i, cx, i + 1);
        printf("%d %d\n%d %d\n", cx, i, cx, i + 1);//가로로 움직인 경우 출력
    }
}
int main() {
    int n, m;
    scanf("%d%d"&n, &m);
    int cross = (n < m ? n : m) & 0x7ffffffe;//대각선으로 움직일 횟수
    int cx = cross - 1, cy = cross - 1;//대각선으로 움직인 후 남은 칸 수
    int move_down = (n-1-cx) & 0x7ffffffe, move_right = (m - 1 - cy) & 0x7ffffffe;//0, 1칸이 남을 때 까지 이동
    cx += move_down;
    cy += move_right;
    
    if (cx != n - 1 && cy != m-1) {//m, n 모두 남았을 때
        print(cross, move_down, move_right, 4);
        printf("%d %d\n%d %d\n", cx, cy + 1, cx + 1, cy + 1);
        printf("%d %d\n%d %d\n", cx, cy + 1, cx + 1, cy + 1);
    }
    else if (cx != n - 1) {//세로로 남은경우
        print(cross, move_down, move_right, 4);
        printf("%d %d\n%d %d\n", cx + 1, cy - 1, cx + 1, cy);
        printf("%d %d\n%d %d\n", cx + 1, cy - 1, cx + 1, cy);
    }
    else if (cy != m - 1) {//가로로 남은경우
        print(cross, move_down, move_right, 4);
        printf("%d %d\n%d %d\n", cx - 1, cy + 1, cx, cy + 1);
        printf("%d %d\n%d %d\n", cx - 1, cy + 1, cx, cy + 1);
    }
    else {//움직인 최종 위치가 목적지 일 때
        print(cross, move_down, move_right, 0);
    }
    
}
 
cs

 

반응형

'알고리즘 문제 > [백준]' 카테고리의 다른 글

[백준] 20120번: 호반우와 리듬게임  (0) 2020.12.03
[백준] 13458 시험 감독  (0) 2020.11.29
[백준] 13907 세금  (2) 2020.11.05
[백준] 16235번 나무 재테크  (0) 2020.11.02
백준 16637 괄호 추가하기  (0) 2020.10.30