[백준] 마법사 상어와 토네이도

유승선 ·2022년 7월 29일
0

백준

목록 보기
37/64

드디어 길고 길었던 마법사 상어 시리즈를 전부 풀었다. 마법사 상어 시리즈는 Matrix 를 이용한 시뮬레이션 연습에 굉장히 좋았다고 생각하지만 솔직히 문제 자체의 설명이 너무나도 어지러워서 정말 짜증났던 시리즈 였던거같다.
지금까지 풀었던 마법사 상어 시리즈는 내가 기억했을때 격자를 만들어서 옮기는 과정, 격자를 돌리는 과정, 각 좌표를 자유롭게 8가지 방향으로 옮기는 등등 좋은 예시가 있었고 이번 문제는 가운데 지점 부터 시작해서 회오리 방향으로 회전 시키는 문제였다.

여기까지만 설명을 들어보면은 괜찮은데, 그 밑에 있었던 저 좌표 설명이 정말 너무 어지러웠어서 다른 사람의 답을 참고해야만 했었다. 저기 있는 해당 좌표에 퍼센트 만큼 옮기고 y 좌표를 옮긴후에 알파 좌표로 옮기는 ... 솔직히 설명 자체도 이해 안가서 구현도 너무 힘들었다. 예시를 더 줬으면 하는 바램이지만 풀이 과정을 적고 느낀점도 적겠다.

되게 어렵게 세팅해놓은 시작 인풋이지만 저 모래 옮기는 과정을 구현하는데 필요한 배열이라고 생각하면 될거같다.

이 부분이 구현을 하는 메인 포인트였는데 격자 밖으로 나가게 되면 답에 더해줘야하는 악랄한 구현이 있었다. 정말 맘에 안드는 과정이었다.

그래도 내가 제일 강조하고 싶은 회전하기 구현이다. 일반적으로 왼쪽에서 시작해서 시계 방향으로 회전하는 구현은 많이 해봤지만 가운데 지점부터 spiral 하는 구현은 익숙치 않아서 많이 헤맸다.

내 블로그에 있는 스파이럴3스파이럴1,2 글의 차이점을 보면은 알 수 있는데. 스파이럴3 에서, 즉 가운데서 시작하는 토네이도는 특정 방향에 따라서 움직이는 범위가 달라진다. 여기 같은 경우 Dir 가 0 혹은 1 일때 범위를 하나씩 늘렸고 주석으로 남긴 글에는 spiral 로 채우는 코드를 테스트 해봤다.

이 외에도, 스파이럴 1,2, 에서는

이런 식으로 채워나갔는데, 각 for 룹에서 내가 i 변수로 채운게 아니고 고정으로 써본 left, bottom 등등을 기준으로 숫자를 늘리고 줄이고 한것도 잘 참고하면 좋겠다.

#include <iostream> 
#include <bits/stdc++.h> 
#define endl "\n"
#define MAX 100010
using namespace std;

int N; 
int matrix[510][510]; 
vector<pair<int,int>> dir = {{0,1},{0,-1},{1,0},{-1,0}}; 
int xdx[4][10] = {{-1,1,-1,1,-1,1,-2,2,0,0},{-1,1,-1,1,-1,1,-2,2,0,0},{0,0,1,1,2,2,1,1,3,2},{0,0,-1,-1,-2,-2,-1,-1,-3,-2}};
int ydx[4][10] = {{0,0,1,1,2,2,1,1,3,2},{0,0,-1,-1,-2,-2,-1,-1,-3,-2},{-1,1,-1,1,-1,1,-2,2,0,0},{-1,1,-1,1,-1,1,-2,2,0,0}};
int percent[9] = {1,1,7,7,10,10,2,2,5};
int answer = 0; 

void Input(){
    cin >> N;
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){
            cin >> matrix[i][j]; 
        }
    }
}

void spread_sand(int x, int y, int Dir){
    int xx = x + dir[Dir].first;
    int yy = y + dir[Dir].second; 
    if(matrix[xx][yy] == 0) return; 

    int sand = matrix[xx][yy];
    int tmp = sand; 
    for(int i = 0; i < 9; i++){
        int nx = x + xdx[Dir][i];
        int ny = y + ydx[Dir][i]; 
        int per = percent[i]; 
        int plus = (tmp * per) / 100; 

        if(nx < 1 || ny < 1 || nx > N || ny > N) answer += plus;
        else matrix[nx][ny] += plus; 

        sand -= plus; 
    }
    int nx = x + xdx[Dir][9];
    int ny = y + ydx[Dir][9]; 

    if(nx < 1 || ny < 1 || nx > N || ny > N) answer += sand; 
    else matrix[nx][ny] += sand;
    matrix[xx][yy] = 0; 
}

bool check(){
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){
            if(matrix[i][j] == 0) return false; 
        }
    }
    return true; 
}

int change_dir(int Dir){
    if(Dir == 0) return 3;
    if(Dir == 1) return 2;
    if(Dir == 2) return 0;
    if(Dir == 3) return 1; 

    return -1; 
}

void Solution(){
    int x = (N+1)/2, y = (N+1)/2, Dir = 1, len = 0; 
    int cnt = 1; 
    matrix[x][y] = cnt++; 
    while(1){
        if(Dir == 0 || Dir == 1) len++; 

        if(len == N){
            for(int i = 0; i < len; i++){
                spread_sand(x,y,Dir); 
                x += dir[Dir].first;
                y += dir[Dir].second; 
                
                // if(x < 1 || y < 1 || x > N || y > N) continue; 
                // matrix[x][y] = cnt++; 
            }
            break; 
        }

        for(int i = 0; i < len; i++){
            spread_sand(x,y,Dir); 
            x += dir[Dir].first;
            y += dir[Dir].second; 
            
            //if(x < 1 || y < 1 || x > N || y > N) continue; 
            //matrix[x][y] = cnt++; 
        }
        Dir = change_dir(Dir); 
    }


    cout << answer; 
}


void Solve(){
    Input();
    Solution(); 
}

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    //freopen("input.txt", "r", stdin);
    Solve();
    return 0;

}

도움을 받은 블로그

배운점:
1. 회오리 채우는 과정에 다른점
2. 시뮬레이션 문제 강화

profile
성장하는 사람

0개의 댓글