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

 

10757번: 큰 수 A+B

두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

수의 범위가 long long의 범위도 넘어가는 경우에는 문자열로 구현해주어야 한다.

이 문제를 풀어놓으면 활용해서 풀 수 있는 문제들이 꽤 있다. (1914 하노이탑, 2407 조합, 10826 피보나치 수 4 등)

15353번 큰 수 A + B (2) 문제는 아예 똑같은 코드로 풀 수 있다.

 

 

먼저 문자열 두 개를 입력받았으면 덧셈을 해주기 위해서 자릿수를 맞춰주어야 한다.

길이를 비교하고 길이가 더 짧은 곳에 0을 붙여준다.

예를 들어 123456과 123456789이라면 123456 앞에 두 수의 길이의 차이인 3만큼 0을 붙여줘서 000123456을 만들어준 후에 덧셈을 진행한다.

 

 

각각의 자리에서 더해주고 9보다 큰 값이 있다면 다음 자릿수의 덧셈에서 1을 더 더해준다.

이런 식으로 정답 문자열에 붙여주면 거꾸로 되므로 마지막에 문자열을 뒤집어준다.

 

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
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    string a, b;
    string ans = "";
    cin >> a >> b;
 
    int n = a.length() - 1;
    int m = b.length() - 1;
 
 
    //자릿수 맞춰준다.
    string tmp = "";
    if (n < m) {
        for (int i = 0; i < m - n; i++) {
            tmp += "0";
        }
        a = tmp + a;
    }
    else if (n > m) {
        for (int i = 0; i < n - m; i++) {
            tmp += "0";
        }
        b = tmp + b;
    }
 
    
    int len = a.size(); //자릿수 위에서 맞춰줬으므로 길이 아무거나 상관없음
    int x, y, z;
    int up = 0;
 
//1의 자리부터 진행
    for (int i = len - 1; i >= 0; i--) {
        x = a[i] - '0';
        y = b[i] - '0';
        z = x + y;
        if (up == 1) {
            z += 1;
            up = 0;
        }
 
 
        if (z > 9) {
            ans += to_string(z % 10);
            up = 1;
        }
        else {
            ans += to_string(z);
        }
    }
    
    if (up == 1) ans += "1";
 
 
    reverse(ans.begin(), ans.end());
 
    cout << ans << '\n';
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 18808. 스티커 붙이기  (0) 2020.03.23
[BOJ] 17822. 원판 돌리기  (0) 2020.03.16
[BOJ] 1331. 나이트 투어  (0) 2020.03.03
[BOJ] 4179. 불!  (0) 2020.02.17
[BOJ] 1938. 통나무 옮기기  (0) 2020.02.12

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AW9j-qfacIEDFAUY&categoryId=AW9j-qfacIEDFAUY&categoryType=CODE

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

이 문제는 구간 누적 합을 메모해 놓을 배열과 최솟값을 메모해 놓을 배열이 각각 필요하다.

 

다음과 같은 로직으로 풀어봤다.

 

  1. 입력받는다.
  2. 누적합을 dp로 만들어 놓는다.
    dp[x][y] = (0, 0)이 왼쪽 시작점 (x, y)과 오른쪽 끝점인 사각형의 누적합
  3. 초콜릿 자르는 모든 경우를 분할정복으로 구해준다.
    1. 가로로 자르는 경우(for문으로 가로 선택하는 모든 경우 구한다)
    2. 세로로 자르는 경우(for문으로 세로 선택하는 모든 경우 구한다)

위의 3번의 모든 경우 중 건포도의 수가 최소인 경우를 구해준다.
하지만 이때 진짜 다 구하면 시간 초과 발생하므로 미리 구해놓은 거는 메모해놨다가 써야 한다.

 

dp[x][y][ex][ey] = 초콜릿의 왼쪽 시작점이 (x, y) 오른쪽 끝점이 (ex, ey) 일 때 초콜릿을 자르는 경우 지불해야 하는 건포도의 최솟값

 

초콜릿의 크기가 클수록 다시 사용되는 부분이 계속 존재하므로 매번 다시 구할 필요가 없다. 그림으로 설명하면

아래 그림처럼 어떻게 잘라도 노란 사각형 부분을 잘랐을 때의 건포도의 최솟값은 동일하기 때문이다.

 

 

누적합을 구하는 방법은 백준의 2167번 2차원 배열의 합(문제 링크)을 푸는 방법과 똑같다.

(풀이 링크)

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
#include <iostream>
#include <cstring>
#define MAX 1000000000
using namespace std;
 
int dp[51][51][51][51];
int choco[51][51];
int sum[51][51];
 
int solve(int x, int y, int ex, int ey) {
    //초코릿 조각이 한개면 0리턴
    if (x == ex && y == ey) return 0;
    //이미 최솟값을 구해놨으면 최솟값 바로 리턴
    if (dp[x][y][ex][ey] != -1) {
        return dp[x][y][ex][ey];
    }
 
    //(x, y)부터 (ex, ey)까지의 건포도의 합
    int cnt = sum[ex][ey] - sum[x - 1][ey] - sum[ex][y - 1+ sum[x - 1][y - 1];
 
 
    int rt = MAX;
 
    //가로로 자르는 경우
    for (int i = x; i < ex; i++) {
        int tmp = solve(x, y, i, ey) + solve(i + 1, y, ex, ey);
        if (rt > tmp + cnt) rt = tmp + cnt;
    }
 
    //세로로 자르는 경우
    for (int i = y; i < ey; i++) {
        int tmp = solve(x, y, ex, i) + solve(x, i + 1, ex, ey);
        if (rt > tmp + cnt) rt = tmp + cnt;
    }
 
 
    //dp메모하고 리턴
    return dp[x][y][ex][ey] = rt;
 
}
 
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
 
    int T;
    cin >> T;
 
    int n, m;
    for (int tc = 1; tc <= T; tc++) {
        //최솟값 dp배열 -1로 초기화
        memset(dp, -1sizeof(dp));
        
        cin >> n >> m;
 
 
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                cin >> choco[i][j];
            }
        }
 
        //누적합
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1- sum[i - 1][j - 1+ choco[i][j];
            }
        }
 
        int ans = solve(11, n, m);
        cout << '#' << tc << ' ' << ans << '\n';
    }
 
 
    return 0;
}
Colored by Color Scripter
 

 

'SWEA > D4' 카테고리의 다른 글

[SWEA] 1486. 장훈이의 높은 선반  (0) 2019.06.27
[SWEA] 1226. [S/W 문제해결 기본] 7일차 - 미로1  (0) 2019.06.27
[SWEA] 7829. 보물왕 태혁  (0) 2019.06.27

먼저 다음과 같이 입력하면 가상 환경 리스트를 볼 수 있다. 

conda info --envs

 

 

가상 환경을 만들어주기 위해 아래처럼 입력하면 python3.5 버전과 함께 가상 환경을 만들어준다. 이렇게 환경마다 다른 버전을 설치할 수 있는 게 가상 환경의 장점이다.

conda create --name 가상환경이름 python=3.5

 

 

생성 중에 다음과 같이 뜨면 y를 누르고 계속 진행해준다. 

 

 

다시 conda info --envs를 통해서 가상 환경 리스트를 보면 방금 만든 가상 환경이 추가되어 있다.

 

이제 activate 명령어로 가상환경을 활성화시켜주면 되는데 Mac에서는 앞에 source를 같이 해줘야 한다.

activate 가상환경이름
source activate 가상환경이름

 

 

 

#conda 4.8.3-py37_0 로 업데이트 후에 아래처럼도 가능하다.

conda activate 가상환경이름 

 

 

 

다시 가상 환경 리스트를 확인해보면 *위치가 이동한 것을 확인할 수 있다.

 

 

반대로 비활성화시킬 때는 deactivate을 해준다.

conda deactivate

 

가상 환경을 삭제할 때는 다음과 같이 입력한다.

conda remove --name 가상환경이름 --all

**활성화된 가상 환경은 삭제할 수 없으므로 deactivate 후에 삭제한다.

 

 

 

사실 아나콘다를 설치하면 함께 설치되는 Anaconda-Navigator 앱의 Environments 탭에서 가상 환경을 쉽게 추가/삭제할 수 있다.

'개발환경설정' 카테고리의 다른 글

[ANACONDA] 아나콘다 MAC에 설치하기 (zsh)  (3) 2020.03.04

https://www.anaconda.com/

 

Anaconda | The World's Most Popular Data Science Platform

Anaconda is the standard platform for Python data science, leading in open source innovation for machine learning. Develop, manage, collaborate, and govern at scale with our enterprise platform.

www.anaconda.com

먼저 위의 사이트에서 아나콘다를 다운로드할 수 있다.

 

우측 상단의 download버튼을 누르고 화면 밑으로 내려가면 다음과 같은 화면이 나온다.

graphical installer로 설치하면 쉽게 설치할 수 있다.

 

 

 

다운로드한 패키지 파일을 실행시켜주고 '계속'을 쭉쭉 눌러주다가 동의 창이 나오면 동의를 눌러주고 진행하면 된다.

 

 

그다음에 설치할 디스크를 선택하는데 특정 디스크를 선택해서 설치한다. 따로 폴더 선택을 해주지 않으면 /opt/anaconda3 경로로 설치된다. 이어서 '계속'을 눌러주면 설치가 끝나는데 시간은 조금 걸린다. 

 

터미널에서 conda를 쳤을 때 쭉쭉쭉 뭐라 나오면 잘 설치된 거다. 아니면 conda --version 으로 버전이 잘 뜨는지 확인한다.

하지만 나는 zsh을 사용하고 있어서 .zshrc 파일에 다음과 같이 추가적인 작업을 해줬다.(.zshrc는 홈 디렉터리 밑에 있다. ls -al로 확인 가능)

 

.zshrc파일 수정

vi ./.zshrc

 

다음과 같이 추가해준다. 아래에서 /opt/anaconda3 부분은 자기가 설치한 경로로 해주면 된다.

export PATH="/opt/anaconda3/bin:$PATH"

 

위에 추가해줘도 바로 적용되지는 않고 재부팅하거나 다음과 같이 터미널에 입력하면 적용된다.

source ./zshrc

 

그러면 이제 아래와 같이 잘 뜬다.

 

 

update까지 해준다.

conda update conda

'개발환경설정' 카테고리의 다른 글

[ANACONDA] 가상환경 만들기(추가/삭제) (MAC)  (0) 2020.03.04

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

 

1331번: 나이트 투어

나이트 투어는 체스판에서 나이트가 모든 칸을 정확히 한 번씩 방문하며, 마지막으로 방문하는 칸에서 시작점으로 돌아올 수 있는 경로이다. 다음 그림은 나이트 투어의 한 예이다. 영식이는 6×6 체스판 위에서 또 다른 나이트 투어의 경로를 찾으려고 한다. 체스판의 한 칸은 A~F 중의 알파벳 하나와 1~6 중의 숫자 하나로 나타낼 수 있다. 영식이의 나이트 투어 경로가 주어질 때, 이것이 올바른 것이면 Valid, 올바르지 않으면 Invalid를 출력하는 프

www.acmicpc.net

  1. 나이트의 이동 경로가 맞는지
  2. 모든 칸을 정확히 한 번씩만 방문했는지
  3. 마지막으로 방문하는 칸에서 시작점으로 돌아올 수 있는지

모든 이동에서 위의 1번과 2번의 경우를 확인해주고 마지막 칸에서 3번 조건을 확인한다.

하나라도 조건에 맞지 않다면 Invalid를 출력하고 모든 조건을 만족한다면 Valid를 출력한다.

 

 

현재 좌표가 x, y 라고 할 때, 나이트가 이동할 수 있는 경로는 위의 그림과 같다.

즉, (x, y)와 이동할 좌표의 차이의 절댓값이

x가 1인 경우에 y는 2이고, x가 2인 경우에 y는 1이면 된다.

 

 

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
#include <iostream>
#include <string>
#include <cmath>
#define MAX 36
using namespace std;
 
 
bool visit[36][36];
 
bool check(int x, int y, int nx, int ny) {
    int diffx = abs(nx - x);
    int diffy = abs(ny - y);
 
    if (diffx == 1 && diffy == 2return true;
    else if (diffx == 2 && diffy == 1return true;
 
    return false;
}
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    bool valid = true;
 
    string now, next;
    
    //시작칸 입력
    cin >> now;
 
    int sx, sy;
    int x, y, nx, ny;
 
    //시작칸 좌표
    sx = now[0- 'A';
    sy = now[1- '1';
    
    int cnt = 1;
    x = sx;
    y = sy;
    visit[x][y] = true;
 
 
    while (cnt++ < MAX) {
        cin >> next;
        if (!valid) continue;
 
 
        nx = next[0- 'A';
        ny = next[1- '1';
 
 
        //방문 확인
        if (visit[nx][ny]) {
            valid = false;
            continue;
        }
 
 
        //방문 표시
        visit[nx][ny] = true;
 
 
        //나이트의 이동경로가 맞는지 검사
        bool flag = check(x, y, nx, ny);
        //나이트의 이동경로로 갈 수 없다면 Invalid
        if (!flag) valid = false;
 
        
        //이동한 좌표를 현재좌표로 바꿔준다.
        now = next;
        x = nx;
        y = ny;
    }
 
 
    //다시 시작칸으로 돌아갈 수 있는지 검사
    if (!check(x,y,sx,sy)) valid = false;
 
 
    if(valid) cout << "Valid" << '\n';
    else cout << "Invalid" << "\n";
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 17822. 원판 돌리기  (0) 2020.03.16
[BOJ] 10757. 큰 수 A + B  (0) 2020.03.10
[BOJ] 4179. 불!  (0) 2020.02.17
[BOJ] 1938. 통나무 옮기기  (0) 2020.02.12
[BOJ] 17780. 새로운 게임  (0) 2020.02.03

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

 

4179번: 불!

문제 지훈이는 미로에서 일을 한다. 지훈이를 미로에서 탈출하도록 도와주자! 미로에서의 지훈이의 위치와 불이 붙은 위치를 감안해서 지훈이가 불에 타기전에 탈출할 수 있는지의 여부, 그리고 얼마나 빨리 탈출할 수 있는지를 결정해야한다. 지훈이와 불은 매 분마다 한칸씩 수평또는 수직으로(비스듬하게 이동하지 않는다)  이동한다.  불은 각 지점에서 네 방향으로 확산된다.  지훈이는 미로의 가장자리에 접한 공간에서 탈출할 수 있다.  지훈이와 불은 벽이 있는 공간

www.acmicpc.net

지훈이가 미로를 탈출할 수 있는 경우에는 가장 빠른 탈출시간을 출력하는 BFS문제이다.

 

 

3055번 탈출 문제(문제 링크)랑 비슷한 것 같다.

탈출 문제에서는 물이 퍼지는 시간을 먼저 BFS로 저장해놓고, 고슴도치가 이동할 곳의 시간이 물이 퍼진시간보다 작은 경우에만 이동할 수 있도록 구현했다. (문제 풀이 링크)

 

 

이번에도 똑같이 풀어봤는데 정답은 뜨지만 메모리를 많이 써서 다른 방법으로 다시 풀어봤다.

먼저 지훈이가 이동할 좌표와 불이 확산될 좌표를 각각 다른 큐에 넣어놓고 이동시킨다.

그리고 매분마다 불을 먼저 이동시키고 지훈이를 이동시키면 불이 확산되지 않은 곳으로 이동할 수 있다.

 

 

(입력받을 때 지훈이의 위치는 지나갈 수 있는 공간이므로 '.'으로 바꿔줘야 한다.)

 

 

미로를 탈출하는 경우는 입력으로 주어지는 지도 밖으로 벗어나는 경우이므로

배열의 크기를 더 크게 잡아서 범위를 벗어나는 경우에 탈출한 것으로 본다.

아래 그림처럼 지도를 (1, 1)부터 입력받으면 지훈이의 위치가 0행이거나 0열이거나 R+1행이거나 C+1 열인 경우 미로를 탈출한다.

 

 

BFS를 진행할 때에는, 먼저 지훈이가 이동할 수 있는 곳이 더 없다면 끝나기 때문에 지훈이의 좌표를 담은 큐가 비었다면 BFS를 종료한다. 그리고 매분마다 불을 먼저 확산시키고 다음에 지훈이를 이동시키기 위해서

각자의 큐사이즈만큼씩만 진행하면 된다.

한 번에 이동할 수 있는 위치만큼(현재 위치로부터 1만큼 이동한 곳)이 큐에 새로 들어가기 때문이다.

 

 

지훈이가 미로를 탈출했다면 그때의 시간을 출력하고 바로 리턴해서 종료시킨다.

이 부분에서 종료되지 않고 BFS탐색을 끝낸다면 탈출이 불가능한 경우이므로 IMPOSSIBLE을 출력하고 종료한다.

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
#include <iostream>
#include <queue>
using namespace std;
 
int r, c;
char map[1001][1001];
bool visit[1001][1001];
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    //불이 이동할 큐
    queue<pair<intint> > fq;
    //지훈이 이동할 큐
    queue<pair<intint> > jq;  
    
 
    cin >> r >> c;
    for (int i = 1; i <= r; i++) {
        for (int j = 1; j <= c; j++) {
            cin >> map[i][j];
 
            if (map[i][j] == 'J') {
                jq.push(make_pair(i, j));
                visit[i][j] = true;
 
                map[i][j] = '.';
            }
            else if (map[i][j] == 'F') {
                fq.push(make_pair(i, j));
                visit[i][j] = true;
            }
        }
    }
 
 
    int x, y;
    int time = 0;
    while (!jq.empty()) {
        int jqsize = jq.size();
        int fqsize = fq.size();
        int nx, ny;
 
        time++;
 
        //불이 먼저 이동
        while (fqsize--) {
            x = fq.front().first;
            y = fq.front().second;
            fq.pop();
 
            for (int k = 0; k < 4; k++) {
                nx = x + dx[k];
                ny = y + dy[k];
                
                //범위 체크
                if (nx <= 0 || ny <= 0 || nx > r || ny > c) continue;
                //벽이면 못간다
                if (map[nx][ny] == '#'continue;
                //방문 체크
                if (visit[nx][ny]) continue;
 
 
                fq.push(make_pair(nx, ny));
                visit[nx][ny] = true;
            }
        }
 
 
        //지훈이 이동
        while (jqsize--) {
            x = jq.front().first;
            y = jq.front().second;
            jq.pop();
 
            for (int k = 0; k < 4; k++) {
                nx = x + dx[k];
                ny = y + dy[k];
 
                //벽이면 못간다
                if (map[nx][ny] == '#'continue;
                //이미 이동한 곳이거나,  불이 이미 확산되어 있거나 같은 시간에 확산된다
                if (visit[nx][ny]) continue;
                
                //탈출한 경우 바로 종료
                if (nx == 0 || ny == 0 || nx == r + 1 || ny == c + 1) {
                    cout << time << '\n';
                    return 0;
                }
 
                jq.push(make_pair(nx, ny));
                visit[nx][ny] = true;
            }
        }
 
 
    }
 
 
    //위에서 종료되지 못한 경우
    cout << "IMPOSSIBLE" << '\n';
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 10757. 큰 수 A + B  (0) 2020.03.10
[BOJ] 1331. 나이트 투어  (0) 2020.03.03
[BOJ] 1938. 통나무 옮기기  (0) 2020.02.12
[BOJ] 17780. 새로운 게임  (0) 2020.02.03
[BOJ] 17837. 새로운 게임 2  (0) 2020.02.03

https://programmers.co.kr/learn/courses/30/lessons/60063

 

코딩테스트 연습 - 블록 이동하기 | 프로그래머스

[[0, 0, 0, 1, 1],[0, 0, 0, 1, 0],[0, 1, 0, 1, 1],[1, 1, 0, 0, 1],[0, 0, 0, 0, 0]] 7

programmers.co.kr

 

백준의 1938번 통나무 옮기기(문제 링크)와 비슷한 느낌의 BFS 문제다.

(통나무 옮기기 풀이 링크)

 

이게 조금 더 어려운 것 같기는 하다...

좌표를 어떻게 저장할까 하다가 아래 카카오 기술 블로그에 있는 해설에서 아이디어를 얻어서 풀었다.

 

https://tech.kakao.com/2019/10/02/kakao-blind-recruitment-2020-round1/

 

2020 신입 개발자 블라인드 채용 1차 코딩 테스트 문제 해설

올해에도 2020이라는 멋진 숫자와 함께, 카카오의 신입 개발자 채용을 시작했습니다! 그 여정 중 첫 단계로 1차 코딩 테스트가 지난 9월 7일 토요일 오후 2시부터 오후 7시까지 5시간 동안 진행됐는데요. 저희 준비위원들도 설렘과 긴장 속에 원활한 진행을 위해 노력했고, 무사히 1차 테스트를 마칠 수 있었습니다. 테스트에는 총 7문제가 출제됐고, 응시자는 5시간 이내에 순서와 상관없이 문제를 해결해야 […]

tech.kakao.com

 

위의 해설에

(r, c, d) : (r, c) 위치에서 d 방향에 있는 칸을 한 칸 더 차지하고 있음이라고 나와있어서

로봇의 x, y좌표, 방향, 시간을 구조체로 저장해 큐에 넣어서 BFS를 진행하였다.

로봇의 나머지 한 칸은 방향 정보를 이용하여 구한다.

 

 

매번 상, 하, 좌, 우로 이동하는 경우와

로봇의 두 칸 중 한 칸에서 시계방향으로 90도 회전하는 경우 / 반시계 방향으로 90도 회전하는 경우

나머지 한 칸에서 시계방향으로 90도 회전하는 경우 /반시계 방향으로 90도 회전하는 경우

이동 가능한 위치(벽이 아니고 범위를 벗어나지 않는 곳)를 계속 큐에 넣어주면서 진행하면 된다.

 

 

 

로봇을 이동시킬 때, 두 칸 중 한 칸만의 좌표를 기준으로 이동시키므로

로봇의 한 칸을 (x, y)라고 하고 다른 한칸을 (xx, yy)라고 했을 때, visit 배열을 (x, y)를 기준으로 방문을 확인하고 큐에도 (x, y)좌표와 (x, y) 기준의 방향이 들어간다.


따라서 (x, y)축을 기준으로 회전할때는 (x, y)의 좌표는 변화가 없고 방향만 변화하므로 새로 큐에 넣을 때도 (x, y) 좌표 그대로와 회전된 새 방향을 넣어준다.

반대로, (xx, yy)를 축으로 (x, y)를 회전한 경우에는 (x, y)를 이동시킨 위치인 (nx, ny)를 기준으로 만들어주기 위해서 방향을 반대로 바꿔주고 큐에 넣어줄 때에도 (xx, yy)가 아닌 (nx, ny) 좌표와 (nx, ny) 기준의 방향을 넣어준다.

 

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
145
146
147
#include <vector>
#include <queue>
using namespace std;
 
int n;
bool visit[100][100][4];
 
int dx[] = { 010-1 };
int dy[] = { 10-10 };
 
//회전할 때 지나칠 곳
int ndx[] = { -1,1,1,-1 };
int ndy[] = { 1,1,-1,-1 };
 
struct Robot {
    int x;
    int y;
    int dir;
    int time;
    Robot(int a, int b, int d, int t) {
        x = a;
        y = b;
        dir = d;
        time = t;
    }
};
 
bool rangeCheck(int x, int y, int xx, int yy) {
    if (x < 0 || x >= n || y < 0 || y >= n) return false;
    if (xx < 0 || xx >= n || yy < 0 || yy >= n) return false;
 
    return true;
}
 
 
int solution(vector<vector<int>> board) {
 
    queue<Robot> q;
    q.push(Robot(0000));
    visit[0][0][0= true;
 
    n = board.size();
    int destX = n - 1;
    int destY = n - 1;
 
    int cnt = 0;
    while (!q.empty()) {
        int x = q.front().x;
        int y = q.front().y;
        int dir = q.front().dir;
        int time = q.front().time;
        q.pop();
 
        //로봇의 나머지 한칸
        int xx = x + dx[dir];
        int yy = y + dy[dir];
 
 
        //로봇의 한칸이라도 도착하면 종료
        if (x == destX && y == destY) return time;
        if (xx == destX && yy == destY) return time;
 
 
        int nx, ny, nxx, nyy;
 
        //우, 하, 좌, 상 이동
        for (int k = 0; k < 4; k++) {
            nx = x + dx[k];
            ny = y + dy[k];
            nxx = xx + dx[k];
            nyy = yy + dy[k];
            
            //이동할 곳의 범위 체크
            if (!rangeCheck(nx, ny, nxx, nyy)) continue;
            //이동할 곳의 방문 체크
            if (visit[nx][ny][dir]) continue;
            //이동할 수 있는지 체크
            if (board[nx][ny] == 1 || board[nxx][nyy] == 1continue;
 
            visit[nx][ny][dir] = true;
            q.push(Robot(nx, ny, dir, time + 1));
 
        }
 
 
        //x,y 를 축으로 90도 회전
        for (int i = 1; i < 4; i += 2) {
            int ndir = (dir + i) % 4;
            nxx = x + dx[ndir];
            nyy = y + dy[ndir];
 
            int rx, ry; //회전하면서 지나갈 곳의 좌표
            if (i == 1) {
                //시계방향 회전인 경우
                rx = x + ndx[ndir];
                ry = y + ndy[ndir];
            }
            else {
                //반시계방향 회전인 경우
                rx = x + ndx[dir];
                ry = y + ndy[dir];
            }
            
            if (!rangeCheck(rx, ry, nxx, nyy)) continue;
            if (visit[x][y][ndir]) continue;
            if (board[nxx][nyy] == 1continue;
            if (board[rx][ry]) continue;
 
            visit[x][y][ndir] = true;
            q.push(Robot(x, y, ndir, time + 1));
        }
        
 
        //xx, yy 를 축으로 90도 회전
        dir = (dir + 2) % 4//xx, yy가 기준이므로 방향이 반대로 바뀐다.
        for (int i = 1; i < 4; i += 2) {
            int ndir = (dir + i) % 4;
            nx = xx + dx[ndir];
            ny = yy + dy[ndir];
 
            int rx, ry; //회전하면서 지나갈 곳의 좌표
            if (i == 1) {
                //시계방향 회전인 경우
                rx = xx + ndx[ndir];
                ry = yy + ndy[ndir];
            }
            else {
                //반시계방향 회전인 경우
                rx = xx + ndx[dir];
                ry = yy + ndy[dir];
            }
 
            if (!rangeCheck(nx, ny, rx, ry)) continue;
            if (board[nx][ny] == 1continue;
            if (board[rx][ry] == 1continue;
 
            ndir = (ndir + 2) % 4;
            if (visit[nx][ny][ndir]) continue;
            visit[nx][ny][ndir] = true;
            q.push(Robot(nx, ny, ndir, time + 1));
        }
        
 
 
    }
 
}
Colored by Color Scripter
 

 

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

 

1938번: 통나무 옮기기

첫째 줄에 주어진 평지의 한 변의 길이 N이 주어진다. (4<=N<=50) 주어진다. 이어서 그 지형의 정보가 0, 1, B, E로 이루어진 문자열로 주어진다. 한 줄에 입력되는 문자열의 길이는 N이며 입력 문자 사이에는 빈칸이 없다. 통나무와 최종 위치의 개수는 1개이다.

www.acmicpc.net

처음 주어진 통나무의 위치로부터 가능한 동작(U, D, R, L, T)을 모두 사용하여 도착지점까지 이동하면 된다.

이동할 때마다 매번 U, D, R, D, T를 해보고 이동이 가능하다면 동작수를 증가시켜서 이동하면 된다.

 

 

 

이동했을 때 범위를 벗어나거나 / 잘려지지 않은 나무가 있는 경우가 아니라면 이동 가능하다.

최소 동작수를 구해야 하므로 이미 갔던 좌표에도 다시 갈 필요가 없다.

하지만 통나무의 방향이 가로방향으로 온 것과 세로 방향으로 온 것은 구분해주어야 한다.

특히, 회전(T)을 할 때에는 3X3 정사각형 위치에 나무가 있거나 범위를 벗어나지 않는지 모두 확인해주어야 한다.

 

 

 

처음 입력받을 때 처음 통나무 위치의 좌표( pair<intint> start[3] )

이동할 위치의 좌표( pair<intint> dest[3] )를 각각 배열에 저장한다.

그리고 실제 이동은 통나무의 길이는 3으로 정해져 있으므로 중심점의 좌표만 이용하여 이동한다.

 

처음 방향은 이어진 두 좌표가 같은 x좌표라면 (같은 행에 있다면) 가로 방향이고

그렇지 않다면(다른 x좌표 == 다른 행) 세로 방향이다.

 중심점의 좌표와 방향을 이용하여 통나무를 이동시킨다.

 

 

 

이동할 통나무의 정보는 Tree라는 구조체를 만들어서 저장하였다.

Tree는 x좌표와 y좌표 dir(방향), cnt(동작수)를 가지고 있다.

방향은 0이면 가로방향 1이면 세로 방향으로 해놓았다.

이동이 가능할 때마다 이동할 중심 좌표의 위치와, 방향, 이전 동작수 +1을 해서 새로 큐에 넣어주면 된다.

 

 

 

최소 동작 수로 이동시키기 위해서 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
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <iostream>
#include <queue>
using namespace std;
 
int n;
char map[50][50];
 
pair<intint> start[3];
pair<intint> dest[3];
 
//도착지점의 방향
int destDir;
 
int dx[] = { -1,-1,-1,0,0,1,1,1 };
int dy[] = { -1,0,1,-1,1,-1,0,1 };
 
 
//visit[x][y][0] = 가로방향인 상태에서 x,y 에 방문
//visit[x][y][1] = 세로방향인 상태에서 x,y에 방문
bool visit[50][50][2];
 
 
struct Tree {
    int x, y;
    int dir;
    int cnt;
    Tree(int i, int j, int d, int c) {
        x = i;
        y = j;
        dir = d;
        cnt = c;
    }
};
 
 
 
bool turn(int x, int y) {
 
    int nx, ny;
    //중심점에 인접한 8방향을 검사
    for (int k = 0; k < 8; k++) {
        nx = x + dx[k];
        ny = y + dy[k];
 
        //범위를 벗어나면 회전 불가능
        if (nx < 0 || ny < 0 || nx >= n || ny >= n) return false;
        //나무 있으면 회전 불가능
        if (map[nx][ny] == '1'return false;
    }
 
 
    //위의 조건에서 걸리지 않으면 회전 가능
    return true;
}
 
 
 
int solve(int x, int y, int dir) {
    queue<Tree> q;
 
      //x좌표, y좌표, 방향, 동작수
    q.push(Tree(x, y, dir, 0));
    visit[x][y][dir] = true;
 
 
    int cnt;
    while (!q.empty()) {
        x = q.front().x;
        y = q.front().y;
        dir = q.front().dir;
        cnt = q.front().cnt;
        q.pop();
 
 
        //도착지점의 중심좌표와 방향이 같다.
        if (x == dest[1].first && y == dest[1].second && dir == destDir) return cnt;
 
 
        int nx, ny;
        if (dir == 0) {
            //통나무의 현재 방향이 가로방향
 
            //U
            nx = x - 1;
            ny = y;
            //범위와 방문 체크
            if (nx >= 0 && !visit[nx][ny][dir]) {
                //이동할 위치에 나무가 있는지 체크
                if (map[nx][ny] == '0' && map[nx][ny - 1== '0' && map[nx][ny + 1== '0') {
                    visit[nx][ny][dir] = true;
                    q.push(Tree(nx, ny, dir, cnt + 1));
                }
            }
 
 
            //D
            nx = x + 1;
            ny = y;
            if (nx < n && !visit[nx][ny][dir]) {
                if (map[nx][ny] == '0' && map[nx][ny - 1== '0' && map[nx][ny + 1== '0') {
                    visit[nx][ny][dir] = true;
                    q.push(Tree(nx, ny, dir, cnt + 1));
                }
            }
 
 
            //L
            nx = x;
            ny = y - 1;
            if (ny -1 >= 0  && !visit[nx][ny][dir]) {
                if (map[nx][ny - 1== '0') {
                    visit[nx][ny][dir] = true;
                    q.push(Tree(nx, ny, dir, cnt + 1));
                }
            }
 
 
            //R
            nx = x;
            ny = y + 1;
            if (ny + 1 < n && !visit[nx][ny][dir]) {
                if (map[nx][ny + 1== '0') {
                    visit[nx][ny][dir] = true;
                    q.push(Tree(nx, ny, dir, cnt + 1));
                }
            }
 
 
            //T
            if (turn(x,y) && !visit[x][y][1]) {
                q.push(Tree(x, y, 1, cnt + 1));
                visit[x][y][1= true;
            }
 
        }
        else {
            //세로 방향
 
            //U
            nx = x - 1;
            ny = y;
            if (nx - 1 >= 0 && !visit[nx][ny][dir]) {
                if (map[nx - 1][ny] == '0') {
                    q.push(Tree(nx, ny, dir, cnt + 1));
                    visit[nx][ny][dir] = true;
                }
            }
 
 
            //D
            nx = x + 1;
            ny = y;
            if (nx + 1 < n && !visit[nx][ny][dir]) {
                if (map[nx + 1][ny] == '0') {
                    q.push(Tree(nx, ny, dir, cnt + 1));
                    visit[nx][ny][dir] = true;
                }
            }
 
 
            //L
            nx = x;
            ny = y - 1;
            if (ny >= 0 && !visit[nx][ny][dir]) {
                if (map[nx - 1][ny] == '0' && map[nx][ny] == '0' && map[nx + 1][ny] == '0') {
                    q.push(Tree(nx, ny, dir, cnt + 1));
                    visit[nx][ny][dir] = true;
                }
            }
 
 
            //R
            nx = x;
            ny = y + 1;
            if (ny < n && !visit[nx][ny][dir]) {
                if (map[nx - 1][ny] == '0' && map[nx][ny] == '0' && map[nx + 1][ny] == '0') {
                    q.push(Tree(nx, ny, dir, cnt + 1));
                    visit[nx][ny][dir] = true;
                }
            }
 
 
            //T
            if (turn(x, y) && !visit[x][y][0]) {
                q.push(Tree(x, y, 0, cnt + 1));
                visit[x][y][0= true;
            }
        }
 
    }
 
    return 0;
}
 
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n;
 
 
    int k = 0;
    int l = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            if (map[i][j] == 'B') {
                start[k].first = i;
                start[k].second = j;
                k++;
                map[i][j] = '0';
            }
            else if (map[i][j] == 'E') {
                dest[l].first = i;
                dest[l].second = j;
                l++;
                map[i][j] = '0';
            }
        }
    }
 
 
    //도착지점의 방향
    //첫번째와 두번째 위치의 x좌표가 같으면 가로방향
    //가로 방향 : 0 , 세로 방향 : 1
    if (dest[0].first == dest[1].first) destDir = 0;
    else destDir = 1;
 
 
 
    //시작위치의 방향
    //첫번째와 두번째 위치의 x좌표가 같으면 가로방향
    //가로 방향 : 0 , 세로 방향 : 1
    if (start[0].first == start[1].first) cout << solve(start[1].first, start[1].second, 0);
    else cout << solve(start[1].first, start[1].second, 1);
 
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1331. 나이트 투어  (0) 2020.03.03
[BOJ] 4179. 불!  (0) 2020.02.17
[BOJ] 17780. 새로운 게임  (0) 2020.02.03
[BOJ] 17837. 새로운 게임 2  (0) 2020.02.03
[BOJ] 1600. 말이 되고픈 원숭이  (0) 2020.02.01

+ Recent posts