본문 바로가기

알고리즘

BOJ 23289 온풍기 안녕!

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

 

23289번: 온풍기 안녕!

유난히 추운 날씨가 예상되는 이번 겨울을 대비하기 위해 구사과는 온풍기를 설치하려고 한다. 온풍기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기

www.acmicpc.net

 

오랜만에 풀어보는 빡구현 문제이다.

문제에서 주어진대로 구현하면되지만, 자잘한 오타 및 잘못된 로직이 있어 시간이 좀 걸렸다.

#include <cstdio>
#include <vector>

using namespace std;
/*
bit 1111: 상하좌우 가능
d(0-based)
0 : 오른쪽
1 : 왼쪽
2 : 위
3 : 아래
*/
int dr[4] = {0,0,-1,1}; //0-based
int dc[4] = {1,-1,0,0};

vector<pair<int, int>> checkPoint;
vector<pair<pair<int, int>, int>> fan;

int R, C, K, W;
int board[20][20];
int wall[20][20];
bool check(int r, int c){
    if(r >= R || c >= C || r <0 || c < 0) return false;
    else return true;
}

int get_bit(int target, int n){
    return (target >> n) & 1;
}

void printBoard(){
    
    for(int i=0;i<R;i++){
    	for(int j=0;j<C;j++){
    		printf("%d ",board[i][j]);
    	}
    	printf("\n");
    }
    printf("\n");
}

void dfs(int r, int c, int d, bool visited[20][20], int depth){

    if(visited[r][c]) return;
    if(!depth) return;

    visited[r][c] = true;
    board[r][c] += depth;
    if(d <= 1){ //좌우 방향
        for(int i=0;i<3;i++){
            int nextr = r + dr[d] + i - 1;
            int nextc = c + dc[d];
            if(!check(nextr, nextc)) continue;
            if(d == 1){//좌
                if(i == 0 && ( get_bit(wall[r-1][c], 3) || get_bit(wall[r-1][c], 1))) continue;
                if(i == 1 && get_bit(wall[r][c], 1)) continue;
                if(i == 2 && ( get_bit(wall[r+1][c], 2) || get_bit(wall[r+1][c], 1))) continue;
            }
            else{//우
                if(i == 0 && ( get_bit(wall[r-1][c], 3) || get_bit(wall[r-1][c], 0))) continue;
                if(i == 1 && get_bit(wall[r][c], 0)) continue;
                if(i == 2 && ( get_bit(wall[r+1][c], 2) || get_bit(wall[r+1][c], 0))) continue;
            }
            //printf("%d %d -> %d %d\n",r,c, nextr, nextc);
            dfs(nextr, nextc, d, visited, depth-1);
        }
    }

    else{ //상하 방향

        for(int i=0;i<3;i++){
            int nextr = r + dr[d];
            int nextc = c + dc[d] + i - 1;
            if(!check(nextr, nextc)) continue;

            if(d == 2){//위
                if(i == 0 && ( get_bit(wall[r][c-1], 0) || get_bit(wall[r][c-1], 2))) continue;
                if(i == 1 && get_bit(wall[r][c], 2)) continue;
                if(i == 2 && ( get_bit(wall[r][c+1], 1) || get_bit(wall[r][c+1], 2))) continue;
            }
            else{//아래
                if(i == 0 && ( get_bit(wall[r][c-1], 0) || get_bit(wall[r][c-1], 3))) continue;
                if(i == 1 && get_bit(wall[r][c], 3)) continue;
                if(i == 2 && ( get_bit(wall[r][c+1], 1) || get_bit(wall[r][c+1], 3))) continue;
            }
            //printf("%d %d -> %d %d\n",r,c, nextr, nextc);
            dfs(nextr, nextc, d, visited, depth-1);
        }
    }

}

void spread(int fanR, int fanC, int d){
    bool visited[20][20] = {false,};
    dfs(fanR + dr[d], fanC + dc[d], d, visited, 5);
}

void wind(){
    for(auto f : fan){
        spread(f.first.first, f.first.second, f.second);
        //printBoard();
    }
}

void adjustBoundary(){

    for(int i=0;i<R;i++){
        if(board[i][0]) --board[i][0];
        if(board[i][C-1]) --board[i][C-1];
    }
    
    for(int j=1;j<C-1;j++){
        if(board[0][j]) --board[0][j];   
        if(board[R-1][j]) --board[R-1][j];   
    }
}

bool checkCheckPoint(){
    
    for(pair<int, int> point : checkPoint){
        if(board[point.first][point.second] < K){
            return false;
        }
    }
    return true;
}

void shake(){

    int diff[20][20] = {0,};

    for(int i=0;i<R;i++){
        for(int j=0;j<C;j++){
            for(int k=0;k<4;k++){
                if(get_bit(wall[i][j],k)) continue;
                int nextr = i + dr[k];
                int nextc = j + dc[k];
                if(!check(nextr, nextc))  continue;
                if(board[i][j] <= board[nextr][nextc]) continue;

                int d = (board[i][j] - board[nextr][nextc])/4;
                diff[i][j] -= d;
                diff[nextr][nextc] += d;
            }
        }
    }

    for(int i=0;i<R;i++){
        for(int j=0;j<C;j++){
            
            board[i][j] += diff[i][j];
        }
    }
}



int main(){

    scanf("%d%d%d",&R,&C,&K);
    for(int i=0;i<R;i++){
        for(int j=0;j<C;j++){
            scanf("%d",&(board[i][j]));
            if(board[i][j]){
                if(board[i][j] < 5) fan.push_back({{i,j}, board[i][j] - 1});
                else checkPoint.push_back({i,j});
                board[i][j] = 0;
            }
        }
    }
    int a, b, c; 
    scanf("%d",&W);
    for(int i=0;i<W;i++){
        scanf("%d%d%d",&a,&b,&c);
        --a;--b;
        if(c){//(a,b)|(a,b+1)
            wall[a][b] |= (1);
            wall[a][b+1] |= (1<<1);
        }
        else{//(a,b)|(a-1,b)
            wall[a][b] |= (1<<2);
            wall[a-1][b] |= (1<<3);
        }
    }


    int answer = 0;
    while(true){

        //1. fan
        wind();
        //printBoard();
        //2. 섞임
        shake();
        //printBoard();
        //3. 1이상인 가장 바깥쪽 온도 1 감소
        adjustBoundary();
        //4. 초콜맇 먹음
        answer += 1;
        //5. K 칸 이상인지 확인
        if(answer > 100 || checkCheckPoint()){
            break;
        }
    }

    printf("%d\n",answer);


    //printBoard();

}

 

첫번째로 틀렸던 부분은 벽을 세우는 부분이다.
굳이 벽을 세울 수 있는지 확인할 필요가 없었는데 (문제 조건에 따라 벽을 세우지 못하는 경우는 주어지지 않음), 조건식을 추가한 것도 모자라 잘못된 조건식을 추가했었다.

    scanf("%d",&W);
    for(int i=0;i<W;i++){
        scanf("%d%d%d",&a,&b,&c);
        --a;--b;
        if(c){//(a,b)|(a,b+1)
            wall[a][b] |= (1);
            if(b+1 < C) wall[a][b+1] |= (1<<1);
        }
        else{//(a,b)|(a-1,b)
            wall[a][b] |= (1<<2);
            if(a-1) wall[a-1][b] |= (1<<3); //a-1 == 0 인 경우도 벽을 세울 수 있음.
        }
    }

 

두번째로 틀렸던 부분은 최외각 방들의 온도를 낮추는 부분이었다.
꼭지점 방의 온도를 2도씩 낮췄었다.

void adjustBoundary(){

    for(int i=0;i<R;i++){
        if(board[i][0]) --board[i][0];
        if(board[i][C-1]) --board[i][C-1];
    }
    
    for(int j=0;j<C;j++){
        if(board[0][j]) --board[0][j];       // <- [0][0], [0][C-1] 두번 내림
        if(board[R-1][j]) --board[R-1][j];   // <- [R-1][0], [R-1][C-1] 두번 내림
    }
}

 

마지막으로 탐색 가능한지 확인하는 부분에서 () 를 잘못 쳤었다.
이 부분은 첫 제출 이전에 확인하여 수정해서 기록이 없다.

시뮬 문제를 풀땐 이런 점을 잘 생각해서 시간을 버리지 않도록 하자.

'알고리즘' 카테고리의 다른 글

BOJ 11964 Fruit Feast  (0) 2022.04.16
BOJ 11997 Load Balancing (Silver)  (0) 2022.03.29
BOJ 17387 선분 교차2  (0) 2022.02.06
BOJ 1341 사이좋은 형제  (0) 2022.02.05
KAKAO 2022 파괴되지 않는 건물  (1) 2022.02.04