본문 바로가기
[백준]

[BaekJoon/백준] 20057번 마법사 상어와 토네이도

by Hevton 2022. 10. 6.
반응형

 

 

정말 많이 헤맸던 문제다.

그리고 자꾸 결과가 0으로만 나오는데, 문제가 어디인지 찾질 못해서 애를 먹었다.

아니 정확히 말하면 디버깅을 효과적으로 하지 못했기에,, 시간을 더 잡아먹은 것이다.

 

 

XCode도 이렇게 못 다루는데 Visual Studio는 어떻게 디버깅하지...

 

 

이번 문제는 이전 글인 2차원 배열 회전하기 를 활용했다.

 

 

핵심 Key Point는 이렇다.

 

1. 방향은 매번 '좌-하-우-상' 으로 전환된다.

2. 화살표의 길이는 1 -> 1 -> 2 -> 2 -> 3 -> 3 -> 4 -> 4 ... 이렇게 짝수번째 마다 증가한다.

3. 배열의 (0,0)에 도착하면 종료한다.

4. 화살표의 도착 지점만을 기준으로 계산하는 게 아니다

5. '버림'을 잘 기억해야 한다.

 

 

난 4번, 5번 부분을 헷갈려서 시간을 많이 잡아먹었다.

 

4번은.. 예를 들어 이번 턴에 3칸 이동한다고 해서, 도착지점인 딱 그 지점만을 기준으로 계산하는게 아니라,,, 한칸씩 세번 이동하면서 매 번 토네이도 흩뿌리기를 시전해야 한다. 이걸 이해하는 데에만 꽤 오랜 시간이 걸렸다.

 

5번은.. 계산 도중에 버림을 사용해야 한다는 지문을 잘 읽어야 한다. floor() 함수를 꼭 이용해주어야 한다.

int x double 의 결과는 double로 나오기 때문에 주의해야 한다.

/*
 문제를 잘못 이해해서 계속해서 결과가 0이 나왔다.
 도착지점 기준이 아니라, 움직이는 경로 한칸 한칸 마다 모두 계산해주어야 한다.
 */

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;


int N;

double f[5][5] = {
    {0, 0, 0.02, 0, 0},
    {0, 0.1, 0.07, 0.01 ,0},
    {0.05, 99, 0, 0, 0},
    {0, 0.1, 0.07, 0.01, 0},
    {0, 0, 0.02, 0, 0}
};

int mx[4] = {0, 1, 0, -1};
int my[4] = {-1, 0, 1, 0};


int OUT_SAND = 0; // 밖을 나간 모래


// 반시계방향 90도 회전
void rotate() {
    
    
    double tmp[5][5];
    
    for(int i = 0; i < 5; i++) {
        
        for(int j = 0; j < 5; j++) {
            
            
            tmp[i][j] = f[j][5 - i - 1];
            
        }
    }
    
    
    memmove(f, tmp, sizeof(f)); // dest, src, size
    
}


// a를 계산해줌
// 계속 0이나와서 멘탈이 흔들렸던 문제. 이유는 바로 이 함수가 문제였다
// (value * 퍼센트) * 2 작업 과정에서,
// value 정수가 퍼센트 소수를 곱한 결과는 소수가 나왔고, 거기에 *2까지 하니..
// 버림을 제대로 해주지 못한 결과가 도출된 것이다.
int calcuate_a(int value) {
    
    // int니까 연산 도중 자동 버림 될듯.
    value = value - (floor(value * 0.1) * 2 + floor(value * 0.07) * 2 + floor(value * 0.01) * 2 + floor(value * 0.02) * 2 + floor(value * 0.05));

    return value;
    
}

// &는 참조로, 여기서 v의 값을 변경해도 원본까지 바뀐다~!
void M_SAND(int sx, int sy, vector<vector<int>>& v) {
    
    int ORI_SAND = v[sx][sy];
    v[sx][sy] = 0;

    
    for(int i = -2; i <= 2; i++) {
        
        for(int j = -2; j <= 2; j++) {
                            
            
            
            int percent = f[i + 2][j + 2];
            int move_sand;
            
            // double은 명확한 비교 안되니까, 10보다 크다 정도로 하면 99가 걸릴거
            if(percent > 10) {
                move_sand = calcuate_a(ORI_SAND);
                
                
            } else {
                
                move_sand = floor(ORI_SAND * f[i + 2][j + 2]);
            }
            
            
            if(i + sx < 0 || i + sx >= N || j + sy < 0 || j + sy >= N) {
                // 밖을 나감
                OUT_SAND += move_sand;
                
            } else {
                // 밖을 안나감
                
                v[i + sx][j + sy] += move_sand;
            }
                        
        }
        
    }
        
}

int main() {
    
    cin >> N;
    
    vector<vector<int>> v(N, vector<int>(N, 0));
    
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < N; j++) {
            cin >> v[i][j];
        }
    }
    
    int COUNT = 0; // 짝수가 될 때 마다 방향을 바꿀거임
    int DIR = 0; // 방향
    int LEN = 1; // 길이
    
    // 출발지점
    int sx = N / 2;
    int sy = N / 2;
    
        
    bool flag = false; // 종료 플래그
    
    while(1) {
        
                
        for(int i = 0; i < LEN; i++) {
            
            sx = sx + mx[DIR];
            sy = sy + my[DIR];
                        
            
            if(sx < 0 || sx >= N || sy < 0 || sy >= N) // 이런일은 없겠지만..
                break;
            
            
            M_SAND(sx, sy, v);
            
            
            if(sx == 0 && sy == 0) {
                flag = true;
                break;
            }
            
            
            
            
        }
        
        if(flag)
            break;
        

        
        COUNT++;
        
        if(COUNT % 2 == 0) { // 짝수가 되면 길이 늘림
            LEN++;
        }
        
        DIR = (DIR + 1) % 4; // 방향 전환
        
        
        rotate();
                
        
    }
    
    cout << OUT_SAND << "\n";
            
}

 

결과가 계속 0이라면, floor를 이용한 버림이 잘 되지 않았을 가능성이 크다.

 

디버깅을 할 때, 모래가 매 순간 이동하는 경우를 프린트해보면 쉽게 문제를 찾을 수 있다.

난 엉뚱한 곳에서 브레이크를 걸고 디버깅해서 시간을 불필요하게 많이 잡아먹었다.

 

예제로 움직임에 대한 스냅샷을 그려주신 분이 있어서, 참고하면 좋을 것 같다.

https://velog.io/@jeewoo1025/백준-20057-마법사-상어와-토네이도

 

 

 


started at 21:40

ended at 24:40

 

 

참고하면 좋은 블로그

https://jaimemin.tistory.com/1721

반응형