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

 

1748번: 수 이어 쓰기 1

첫째 줄에 N(1≤N≤100,000,000)이 주어진다.

www.acmicpc.net

1부터 n까지 숫자를 이어써서 새로운 숫자를 만들면 그 숫자의 길이를 구하는 문제이다.

예를 들어서 n이 12인 경우 123456789101112 이다.

 

이 문제는

1부터 9는 1자리

10부터 99는 2자리

100부터 999는 3자리인 것을 이용해서 풀면 된다.

 

n이 다음 범위보다 작은 경우에는 n까지의 자리만 구하도록 잘 처리해주는 것이 중요하다.

그렇지 않은 경우에는 그냥 (길이 * 9 * i )를 해주면 된다.

문제에 나와있는 120을 예로 들면

 

처음에는

1 * 9 * 1

2 * 9 * 10

3 * ( 120- 100 + 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
#include <iostream>
using namespace std;
 
int main() {
    int n;
    cin >> n;
 
    int ans = 0;
    int len = 0;
    for (int i = 1; i <= n; i*=10) {
        len += 1;
        if (n < i*10) {
            ans += len*(n - i + 1);
            
        }
        else {
            ans += len * 9 * i;
        }
        
    }
 
    cout << ans;
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 13458. 시험 감독  (0) 2019.07.03
[BOJ] 2529. 부등호  (0) 2019.07.03
[BOJ] 1107. 리모컨  (0) 2019.07.03
[BOJ] 14442. 벽 부수고 이동하기 2  (0) 2019.06.28
[BOJ] 2206. 벽 부수고 이동하기  (0) 2019.06.28

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

 

1107번: 리모컨

첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다.  둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼이 주어지며, 같은 버튼이 여러 번 주어지는 경우는 없다.

www.acmicpc.net

어떤 버튼이 고장 났는지 주어졌을 때, 채널 N으로 이동하기 위해서 버튼을 최소 몇 번 눌러야 하는지를 구하는 문제이다.

 

 

먼저 고장나 있는 버튼을 입력받을 때 최대 10개밖에 안되므로 bool 배열에 미리 체크해놓고 검사해야 할 때 이용한다.

 

 

최소 몇 번 이동했는지를 저장해줄 변수 cnt의 초기값으로 n-100을 해서 +나 -버튼만으로 이동하는 경우를 먼저 넣어 놓고 비교를 해나간다.

최소 횟수를 구하기 위해서 모든 채널에서부터 n으로 가는 모든 경우를 구해줄 것이다.

이동할 채널 N은 500,000 까지이지만 버튼이 고장 나 있는 경우 더 뒤의 채널에서 이동하는 게 더 빠를 수 도 있으므로

0번 채널부터 10,000,00번 채널까지의 경우를 모두 해준다.

해당 채널을 누를 때 버튼이 고장 나있는지 매번 확인해주고 고장 나 있는 경우는 누를 수 없으므로 넘어간다.

 

 

고장 난 버튼을 검사하기 위해서는 check함수를 구현하였다. 누를 버튼 번호를 받아서 % 연산을 이용해 한 자리씩 떼준다.

떼낸 숫자가 고장난 버튼일 경우 바로 0을 리턴해주고 아닐 경우에는 길이 값을 늘려준다.

고장 난 버튼이 하나도 없을 경우 길이 값을 리턴한다.

(0인 경우는 나눠줄 수 없으므로 따로 처리해줘야 한다!)

 

 

길이를 받아왔다면 해당 채널로부터 n까지 +나 -로 몇 번 만에 이동하는지를 구해서 더해준 뒤에 최솟값과 비교해주면 된다.

 
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
#include  <iostream>
using namespace std;
int n, m;
bool broken[11];
int check(int num) {
    
    //0을 나눌 수 없으므로 따로 처리
    if (num == 0) {
        if (broken[0]) {
            return 0;
        }
        else {
            return 1;
        }
    }
 
 
    int len= 0;
    while (num > 0) {
 
        //num을 한 자리씩 떼서 검사해준다.
        //하나라도 고장이면 0을 return
        if (broken[num % 10]) {
            return 0;
        }
 
        //고장나지 않았으면 길이 증가하고 검사한 자리는 없애준다.
        len++;
        num /= 10;
    }
 
    //고장난 버튼이 없었다면 길이를 return
    return len;
}
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
 
 
    //input
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int x;
        cin >> x;
        broken[x] = true;
    }
 
 
    int cnt;
    //+, - 버튼만 사용하는 경우
    cnt = n - 100;
    if (cnt < 0) {
        cnt = -cnt;
    }
 
 
    //모든 번호 에서 n번으로 이동해보면서 몇 번 눌러야하는지 계산
    //번호가 고장나서 누르지 못하는 경우는 넘어간다.
    for (int i = 0; i < 1000000; i++) {
        
        //고장났는지 확인해준다.
        //고장이 나지 않았다면 버튼을 누르는 횟수를 받아온다.
        int len = check(i);
        if (len == 0continue;
 
 
        //현재 i번을 숫자로 누른 상태에서 N까지
        //몇 번 +나 -로 이동해야하는지
        int tmp = n - i;
        if (tmp < 0) {
            tmp = -tmp;
        }
        if (cnt > tmp + len) {
            cnt = tmp + len;
        }
    }
 
    cout << cnt;
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2529. 부등호  (0) 2019.07.03
[BOJ] 1748. 수 이어 쓰기 1  (0) 2019.07.03
[BOJ] 14442. 벽 부수고 이동하기 2  (0) 2019.06.28
[BOJ] 2206. 벽 부수고 이동하기  (0) 2019.06.28
[BOJ] 3055. 탈출  (0) 2019.06.27

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

 

14442번: 벽 부수고 이동하기 2

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

www.acmicpc.net

 

벽 부수고 이동하기 문제와 거의 같은 문제있은데 이 문제에서는 벽을 K개 까지 부수고 이동하여도 된다.

K의 범위는 K(1 ≤ K ≤ 10) 이렇다.

 

이전 문제에서는 부수지 않은 경우와 부순 경우를 0과 1로 구분하였지만

여기서는 부수지 않은 경우부터 k번 부순 경우까지를 0~k로 구분한다.

즉 z == 0 이어야만 부술수 있는 게 아니고 z 가 k보다 작으면 부술 수 있다.

 

마찬가지로 최솟값을 찾을 때에도 d[n-1][m-1][0]부터 d[n-1][m-1][k]까지 모두 비교해주면 된다.

벽 부수고 이동하기 첫 번째 문제를 풀었다면 쉽게 풀릴 문제이긴 하지만

나는 바보같은 짓을 많이 해서 계속 틀렸었다.

마지막에 최솟값을 구하는 부분의 반복문에서 사용한 i를 사용 안 하고 k로 써놔서 계속 50 퍼쯤에서 틀렸었다ㅠㅠ

 다시 바보같은 실수를 하지 말자는 의미에서 적어놔야겠다...

 

 

또, 이 문제를 통해서 main함수 안에서 크기가 큰 배열을 선언하면 안 된다는 것을 알게 되었다...

c++에 대해서 또 하나 배워간다.

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
#include <cstdio>
#include <queue>
using namespace std;
 
int map[1000][1000];
int d[1000][1000][11];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
 
int main() {
 
   
    int n, m, k;
    scanf("%d %d %d"&n, &m, &k);
 
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            scanf("%1d"&map[i][j]);
        }
    }
 
 
    //시작칸 큐에 넣는다.
    queue<pair<pair<intint>int> > q;
    q.push(make_pair(make_pair(0,0),0));
 
    //시작칸도 포함이므로 1부터 시작
    d[0][0][0= 1;
 
 
    //bfs
    while(!q.empty()) {
        int x = q.front().first.first;
        int y = q.front().first.second;
        int z = q.front().second;
        q.pop();
 
        for(int i=0; i<4; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
 
            //범위 체크
            if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
            
            //벽인 경우
            //최대 벽을 부술수 있는 횟수인 k번을 넘어가지 않았다면 부수고 이동
            if(map[nx][ny] == 1 && z < k && d[nx][ny][z+1== 0) {
                q.push(make_pair(make_pair(nx,ny),z+1));
                d[nx][ny][z+1= d[x][y][z] + 1;
            } else if(map[nx][ny] == 0 && d[nx][ny][z] == 0) { //길인 경우
                q.push(make_pair(make_pair(nx,ny),z));
                d[nx][ny][z] = d[x][y][z] + 1;
            }
            
        }
        
    }
 
 
    
    //이동 최대값보다 1큰 값을 넣어 놓는다.
    int min =  m*n+1;
 
 
    //벽을 부수지 않고 도착한 경우부터 k번 부순 경우까지 모두 비교해서 최솟값을 찾는다.
    for(int i=0; i<=k; i++) {
        if(d[n-1][m-1][i] != 0 && min > d[n-1][m-1][i]) {
            min = d[n-1][m-1][i];
        }
    }
 
    //처음 저장해놓은 값 그대로이면 도착하지 못한 경우이므로 -1을 출력
    if(min == m*n+1) {
        printf("%d",-1);
    } else {
        printf("%d",min);
    }
 
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1748. 수 이어 쓰기 1  (0) 2019.07.03
[BOJ] 1107. 리모컨  (0) 2019.07.03
[BOJ] 2206. 벽 부수고 이동하기  (0) 2019.06.28
[BOJ] 3055. 탈출  (0) 2019.06.27
[BOJ] 14501. 퇴사  (0) 2019.06.27

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

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동

www.acmicpc.net

시작 칸에서 마지막 칸까지의 최단 거리를 구하는 문제이기 때문에 bfs로 풀 수 있다.

다른 분의 풀이를 보니 dfs로 엄청 효율적으로 푸셨는데 코드 참고해서 나도 다시 풀어봐야겠다...

 

 

먼저 이 문제에서 중요한 포인트는 벽을 한 개 부수고 이동할 수 있다는 점이다. 이 부분이 이 문제의 어려운 점이다

즉, (x, y)칸에 도착했을 때 그 칸에 그냥 왔는지와 벽을 부수고 왔는지 구분해 주어야한다.

그래서 3차원 배열로 구현했다. 벽을 부수지 않은 경우[x][y][0], 부 순경 우 [x][y][1] 에 이동 경로를 저장했다.

이동할 칸이 벽인 경우, 아직 벽을 부수지 않았고 해당 칸에 아직 방문하지 않았으면 벽을 부수고 이동할 수 있다.

길인 경우에는 그냥 방문하지 않았으면 바로 큐에 넣어준다.

 

 

개인적으로 은근히 헷갈렸던 부분은 이동 경로의 최솟값을 찾아주는 부분이었다.

우선 (n-1, m-1) 칸에 저장되어 있기는 하지만, 벽을 부수고 온 경우가 더 적은 지 벽을 부수지 않고 바로 온경우가 더 적은지

알 수 없으므로 비교해주어야 한다. 그리고 두 곳에 모두 값이 0이라면 -1을 출력해주어야 한다.

나는 먼저 바로 온 경우(d[n-1][m-1][0])을 최솟값(min)으로 해놓고 벽을 부수고 온 경우(d[n-1][m-1][1])가 0이 아닌 경우에 값을 다시 비교해주었다.

 

 

결과적으로 둘 다 0 값을 가지고 있으면 min값도 0이 되므로 도착하지 못한 경우가 되고 -1을 출력한다.

그렇지 않은 경우에는 최솟값을 가지고 있는 min을 출력해준다.

 

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
#include <cstdio>
#include <queue>
using namespace std;
 
int map[1000][1000];
int d[1000][1000][2];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
 
int main() {
 
   
    int n, m;
    scanf("%d %d"&n, &m);
 
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            scanf("%1d"&map[i][j]);
        }
    }
 
 
    //시작 칸을 큐에 넣어준다.
    queue<pair<pair<intint>int> > q;
    q.push(make_pair(make_pair(0,0),0));
 
    //시작칸도 포함이므로 1부터 시작
    d[0][0][0= 1;
 
 
    while(!q.empty()) {
        int x = q.front().first.first;
        int y = q.front().first.second;
        int z = q.front().second;
        q.pop();
 
        for(int i=0; i<4; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
 
            //범위 체크
            if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
            
            //벽인 경우
            //z == 0 이고 (벽을 부수지 않았고), 벽을 부순상태인 다음 칸에 아직 방문하지 않은 경우
            if(map[nx][ny] == 1 && z == 0 && d[nx][ny][1== 0) {
                q.push(make_pair(make_pair(nx,ny),1));
                d[nx][ny][1= d[x][y][z] + 1;
            } else if(map[nx][ny] == 0 && d[nx][ny][z] == 0) {
 
                //길인 경우 이동할 칸에 방문하지 않았으면 방문
                q.push(make_pair(make_pair(nx,ny),z));
                d[nx][ny][z] = d[x][y][z] + 1;
            }
            
        }
        
    }
 
 
    //마지막칸의 최솟값을 찾아준다.
    int min =  d[n-1][m-1][0];
    if(min != 0) {
        if(d[n-1][m-1][1!= 0 && min > d[n-1][m-1][1]) {
            min = d[n-1][m-1][1];
        }
    } else {
        if(d[n-1][m-1][1!= 0) {
            min = d[n-1][m-1][1];
        }
    }
 
 
    //도착하지 못한 경우 -1을 출력
    if(min == 0){
        printf("%d"-1);
    } else {
        printf("%d",min);
    }     
 
    return 0;
}
Colored by Color Scripter
 

 

 

'BOJ' 카테고리의 다른 글

[BOJ] 1107. 리모컨  (0) 2019.07.03
[BOJ] 14442. 벽 부수고 이동하기 2  (0) 2019.06.28
[BOJ] 3055. 탈출  (0) 2019.06.27
[BOJ] 14501. 퇴사  (0) 2019.06.27
[BOJ] 1697. 숨바꼭질  (0) 2019.06.27

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

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net

N의 범위가 1부터 15이므로 완전 탐색으로 쉽게 풀어줄 수 있다.

1부터 N까지의 날짜에 대해 해당 날짜에 상담을 하는 경우하지 않는 경우의 금액을 모두 계산하여 최댓값을 구한다.

주의 할점은 상담할 날로부터의 상담일수가 퇴사하는 날을 넘어가면 안된다.

이부분의 처리만 잘 해주면 된다.

 

자세한 설명은 아래 코드에서!

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
#include <cstdio>
using namespace std;
 
int n;
int max;
int t[16];
int p[16];
 
void solve(int index, int sum) {
    if(index > n) {
 
        //퇴사하는 날짜가 되었으면 최댓값을 계산
 
        if(max < sum) {
            max = sum;
        }
        return;
    }
 
 
    //index번째 날짜에 상담을 하지 않는 경우
    solve(index+1,sum);
 
 
    //퇴사하는 날(n+1)을 넘어가지 않는 경우에만 index번째 날 상담을 진행
    if(index+t[index] <= n+1)
        //상담에 소요되는 날짜와 수익을 더해서 넘겨준다
        solve(index+t[index],sum+p[index]);
 
}
 
int main() {
 
    scanf("%d"&n);
 
    for(int i=1; i<=n; i++) {
        scanf("%d %d"&t[i],&p[i]);
    }
 
 
    max = 0;
    solve(1,0);
    printf("%d", max);
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 2206. 벽 부수고 이동하기  (0) 2019.06.28
[BOJ] 3055. 탈출  (0) 2019.06.27
[BOJ] 1697. 숨바꼭질  (0) 2019.06.27
[BOJ] 7569. 토마토 (3차원)  (0) 2019.06.27
[BOJ] 7576. 토마토  (0) 2019.06.27

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

 

1697번: 숨바꼭질

문제 수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다. 수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지

www.acmicpc.net

수빈이가 동생을 찾을 수 있는 가장 빠른 시간을 구하는 문제이므로 bfs를 사용하면 된다.

수빈이가 갈 수 있는 모든 칸(정점)으로 1초마다 이동하고 방문한 칸은 가지 않는다.(최소 시간이 아니기 때문)

 

먼저 수빈이의 위치 n을 큐에 넣어주고 문제에 나온  x-1, x+1, 2*x 로 각각 이동해준다.(범위를 벗어나지 않는다면)

방문한 경우 visit배열에 걸린 시간을 저장해주고 큐에 넣어준다.

동생의 위치에 도착한 경우(visit[k]에 이동 시간이 저장되어 초기값 -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
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
 
 
 
int main() {
    int n, k;
    int visit[100001];
    memset(visit,-1,sizeof(visit));
    
    scanf("%d %d"&n, &k);
 
    queue<int> q;
 
 
    //수빈이의 위치
    q.push(n);
    visit[n] = 0;
 
 
    //bfs
    while(!q.empty()) {
        int x = q.front();
        q.pop();
 
 
        //x-1로 가는 경우
        //먼저 범위 체크후에 방문하지 않았으면 방문
        if(x-1 >= 0) {
            if(visit[x-1== -1) {
                q.push(x-1);
                visit[x-1= visit[x] + 1;
            }
        }
        
 
        //x+1로 가는 경우
        //먼저 범위 체크 후에 방문하지 않았으면 방문
        if(x+1 < 100001) {
            if(visit[x+1== -1) {
                q.push(x+1);
                visit[x+1= visit[x] + 1;
            }
        }
        
 
        //2*x로 가는 경우
        //먼저 범위 체크 후에 방문하지 않았으면 방문
        if(2*< 100001) {
 
            if(visit[2*x] == -1) {
                q.push(2*x);
                visit[2*x] = visit[x] + 1;
            }
        }
        
 
        //동생의 위치에 도착했으면 더 탐색하지 않는다.
        if(visit[k] != -1) {
            break;
        }
 
    }
 
    
    printf("%d", visit[k]);
    return 0;
 
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 3055. 탈출  (0) 2019.06.27
[BOJ] 14501. 퇴사  (0) 2019.06.27
[BOJ] 7569. 토마토 (3차원)  (0) 2019.06.27
[BOJ] 7576. 토마토  (0) 2019.06.27
[BOJ] 11724. 연결 요소의 개수  (0) 2019.06.27

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

 

7569번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N과 쌓아올려지는 상자의 수를 나타내는 H가 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M ≤ 100, 2 ≤ N ≤ 100, 1 ≤ H ≤ 100 이다. 둘째 줄부터는 가장 밑의 상자부터 가장 위의 상자까지에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 하나의 상자에 담긴 토마토의 정보가 주어진다. 각 줄에는 상자 가로줄에 들어있는 토마

www.acmicpc.net

7576번 문제와 거의 똑같은 문제인데 범위가 조금 더 적고 대신에 상자가 3차원이다.

처음에 똑같은 상자가 h만큼 있는걸로 문제를 오해해서 잘못 풀었었다...;;

7576번 문제에서 3차원으로만 바꿔주면 되지만 나는 c++에 아직 익숙하지 않아서 조금 어려움을 겪었다ㅠㅠ

 

먼저 큐에 저장 하는 방식

2차원에서는 x와 y좌표만 넣어주면 되므로 pair를 사용하였지만 이 문제에서는 z좌표 까지 함께 넣어야한다.

처음에는 tuple을 사용하려 했지만 값을 받아오는 방법이 불편해서 다들 pair를  이중으로 쓴다길래 따라했다..

 

queue<pair<pair<int,int>int>> q;

 

이런식으로 pair를 중첩해서 넣어줬다. (x, y) 가 먼저 pair 가 되고, (x, y) 가 다시 z와 pair가 된다.

이렇게 pair만 3차원 방식에 맞게 구현해주면 나머지는 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
80
81
#include <cstdio>
#include <queue>
using namespace std;
int n,m,h;
int box[100][100][100];
int day[100][100][100];
int dx[] = {0,0,1,-1,0,0};
int dy[] = {1,-1,0,0,0,0};
int dz[] = {0,0,0,0,1,-1};
 
 
int main() {
 
    scanf("%d %d %d"&m, &n, &h);
    queue<pair<pair<int,int>,int> > q;
 
 
    for(int k=0; k<h; k++) {
        for(int i=0; i<n; i++) {
            for(int j=0; j<m; j++) {
 
                scanf("%d"&box[i][j][k]);
                day[i][j][k] = -1;
                //익은 토마토인 경우 큐에 넣는다.
                if(box[i][j][k] == 1) {
                    q.push(make_pair(make_pair(i,j),k));
                    day[i][j][k] = 0;
                }
             
            }
        }
    }
  
 
    while(!q.empty()) {
        int x = q.front().first.first;
        int y = q.front().first.second;
        int z = q.front().second;
        q.pop();
 
        for(int i=0; i<6; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
            int nz = z+dz[i];
            
            //범위 체크
            if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
            if(nz < 0 || nz >= h) continue;
 
            //안익은 토마토 && 아직 방문 안함
            if(box[nx][ny][nz] == 0 && day[nx][ny][nz] == -1) {
                q.push(make_pair(make_pair(nx,ny),nz));
                day[nx][ny][nz] = day[x][y][z] + 1;
            }
        }
 
    }
 
 
    int ans = 0;
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            for(int k=0; k<h; k++) {
                if(box[i][j][k] == 0 && day[i][j][k] == -1) {
                    ans = -1;
                    break;
                }
 
                if(ans < day[i][j][k])
                    ans = day[i][j][k];
            }
            if(ans == -1break;
            
        }
        if(ans == -1break;
    }
 
    printf("%d", ans);
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 14501. 퇴사  (0) 2019.06.27
[BOJ] 1697. 숨바꼭질  (0) 2019.06.27
[BOJ] 7576. 토마토  (0) 2019.06.27
[BOJ] 11724. 연결 요소의 개수  (0) 2019.06.27
[BOJ] 2178. 미로 탐색  (0) 2019.06.25

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

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마

www.acmicpc.net

이 문제는 전형적인 bfs 문제이다.

상자에 있는 토마토가 상하좌우로 하루에 하나씩 익어가는데 모든 토마토가 익는데 걸리는 최소 일수를 구해야 하므로 bfs를 사용하면 된다.

기존에 익어있는 토마토로부터 익으므로 입력받을 때 익은 토마토인 경우 바로 큐에 넣어준다.

상하좌우를 탐색하며 방문하지 않은 토마토에 방문하여 소요 날짜를 저장한다.

 

 

탐색이 끝난 이후에는 문제의 조건에 따라 토마토가 모두 익지는 못하는 상황이라면 -1을 출력하기 위해서

안 익은 토마토인데 방문하지 않은 토마토를 찾는다. 혹시 존재한다면 ans는 -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
#include <cstdio>
#include <queue>
using namespace std;
int n,m;
int box[1000][1000];
int day[1000][1000];
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
 
 
int main() {
 
    scanf("%d %d"&m, &n);
    queue<pair<int,int> > q;
 
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            scanf("%d"&box[i][j]);
 
            //익는데 걸리는 날짜를 저장할 배열 -1로 초기화
            day[i][j] = -1;
 
            //익은 토마토인 경우 큐에 넣는다.
            if(box[i][j] == 1) {
                q.push(make_pair(i,j));
                day[i][j] = 0;
            }
        }
    }
 
 
    //bfs
    while(!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
 
        for(int i=0; i<4; i++) {
            int nx = x+dx[i];
            int ny = y+dy[i];
 
            //범위 체크
            if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
 
            //안익은 토마토 && 아직 방문 안함
            if(box[nx][ny] == 0 && day[nx][ny] == -1) {
                q.push(make_pair(nx,ny));
 
                //소요 일수를 저장 (이전 칸보다 하루 증가)
                day[nx][ny] = day[x][y] + 1;
            }
        }
 
    }
 
 
    //탐색 종료 후에 안익은 토마토가 있는지를 검사 
    int ans = 0;
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
 
            //안 익은 토마토가 있는데 방문하지 않았다.
            if(box[i][j] == 0 && day[i][j] == -1) {
                ans = -1;
                break;
            }
 
 
            //가장 마지막에 익은 토마토의 날짜를 구해야하므로
            //최댓값을 ans에 저장한다. 
            if(ans < day[i][j])
                ans = day[i][j];
        }
        //위의 반복문에서 안익은 토마토가 있는 경우 빠져나와서 break
        if(ans == -1break;
    }
 
    printf("%d", ans);
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1697. 숨바꼭질  (0) 2019.06.27
[BOJ] 7569. 토마토 (3차원)  (0) 2019.06.27
[BOJ] 11724. 연결 요소의 개수  (0) 2019.06.27
[BOJ] 2178. 미로 탐색  (0) 2019.06.25
[BOJ] 4963. 섬의 개수  (0) 2019.06.25

+ Recent posts