ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 10711] 모래성
    C 프로그래밍/BOJ 2022. 10. 23. 21:00
    728x90

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

     

    10711번: 모래성

    첫째 줄에는 모래성의 가로세로 격자 크기 H, W가 주어진다. (1 ≤ H, W ≤ 1,000) 그 다음 H줄에 걸쳐 W개의 문자로 모래성의 상태를 나타내는 문자가 들어온다. 각 문자는 1~9 사이의 숫자, 또는 '.' 이

    www.acmicpc.net

    #include <cstdio>
    #include <queue>
    #include <cstring>
    int R, C;
    char board[1000 + 2][1000 + 2];
    int A[1000 + 2][1000 + 2];
    
    struct _st
    {
    	int x, y;
    };
    std::queue<_st> Q;	// 큐 안에는 "모래"가 담겨있다. 
    std::queue<_st> Buffer;
    
    
    
    void input()
    {
    	scanf("%d %d", &R, &C);
    	for (int i = 0; i < R; i++) {
    		scanf("%s", &board[i]);
    		for (int j = 0; j < C; j ++) {
    			if (board[i][j] == '.') {	// 모래를 기준으로 생각해야 시간초과 나지 않는다 !
    				Q.push({ i, j });
    				A[i][j] = 0;
    			}
    			else A[i][j] = board[i][j] - '0';
    		}
    	}
    }
    
    
    void chk_sand()
    {
    	// dir
    	int dir_x[8] = { 1, 1, 1, 0, 0, -1, -1, -1 };
    	int dir_y[8] = { 0, 1, -1, -1, 1, 0, 1, -1 };
    
    	Buffer = {};
    
    	while (!Q.empty()) {
    		_st data = Q.front();
    		Q.pop();
    
    		for (int p = 0; p < 8; p++) {
    			int nx = data.x + dir_x[p];
    			int ny = data.y + dir_y[p];
    
    			if (nx < 0 || nx > R - 1 || ny < 0 || ny > C - 1) continue;
    			if (A[nx][ny] == 0) continue;
    			if (A[nx][ny] > 0 ) {
    				A[nx][ny] -= 1;
    				if (A[nx][ny] == 0) Buffer.push({ nx, ny });
    			}
    		}
    	}
    	Q = Buffer;
    }
    
    
    int Flood_Fill()
    {
    	int wave = 0;
    	while (1) {
    		chk_sand();
    		if (Q.empty()) return wave;	// 더이상 모래가 되는 애가 없다면
    		wave++;
    	}
    }
    
    
    int main()
    {
    	input();
    	int ans = Flood_Fill();
    	printf("%d\n", ans);
    	return 0;
    }

     

    '시간초과' 3번은 모래성을 기준으로 (1) Flood-Fill + 맵복사 / (2) 버퍼큐 + 맵복사 / (3) 큐 + 벡터에 0되는 좌표 저장 후 0으로 변경하는 방식을 사용했었다. 

    이렇게 구현하면 불필요한 연산이 많아지는데, 그 이유는 모래성을 기준으로 파도가 밀려올 때 마다 주변을 다 탐색해야 하기 때문이다. 이전 탐색 때 0이었던 곳은 새로운 탐색 때도 0이다. 따라서 BFS를 돌리면서 새롭게 0이 되는 곳 만 버퍼큐에 넣어주고, 큐를 계속 갱신하는 과정을 거친다면 이전에 탐색했던 곳을 중복으로 탐색하는 것을 막을 수 있다. 

     

     

    따라서 가장 처음 맵을 입력받을 때, 0인 좌표를 Q에 저장한다. 

    이후 BFS 탐색을 통해 인접 8구역에 모래가 있다면 1을 감소시킨다. 만약 이렇게 감소시킨 모래가 0이 된다면 버퍼큐에 저장하고, 값 리턴 전 Q에 복사한다. 

    만약 BFS 함수가 리턴한 Q의 사이즈가 0이면, 0이되는 모래가 없다는 뜻이므로 모래성의 모양이 더 이상 변화하지 않게 된다는 의미와 같다. 

     


    ++22.11.09 갱신

    1000 * 1000 맵이므로 while 루프를 여러번 돌리면 시간 초과날 확률이 굉장히 크다.

    따라서 BFS를 한번만 돌리고 값을 구하려고 해야한다. 

    생각하자 생각.. 맵 사이즈가 이렇게 커지면 완전탐색으로는 타임아웃 난다. 

    그리고 컨테이너 안에 어떤 정보가 담겨 있는지 잘 생각하자. 

    #include <cstdio>
    #include <queue>
    #include <cstring>
    int R, C;
    char board[1000 + 2][1000 + 2];
    int A[1000 + 2][1000 + 2];
    
    struct _st
    {
    	int x, y;
    	int time;
    };
    std::queue<_st> Q;	// 큐 안에는 "모래"가 담겨있다. 
    
    
    void input()
    {
    	scanf("%d %d", &R, &C);
    	for (int i = 0; i < R; i++) {
    		scanf("%s", &board[i]);
    		for (int j = 0; j < C; j ++) {
    			if (board[i][j] == '.') {	// 모래를 기준으로 생각해야 시간초과 나지 않는다 !
    				Q.push({ i, j, 0 });
    				A[i][j] = 0;
    			}
    			else A[i][j] = board[i][j] - '0';
    		}
    	}
    }
    
    
    int BFS()
    {
    	// dir
    	int dir_x[8] = { 1, 1, 1, 0, 0, -1, -1, -1 };
    	int dir_y[8] = { 0, 1, -1, -1, 1, 0, 1, -1 };
    
    	_st data = {};
    	while (!Q.empty()) {
    		data = Q.front();
    		Q.pop();
    
    		for (int p = 0; p < 8; p++) {
    			int nx = data.x + dir_x[p];
    			int ny = data.y + dir_y[p];
    
    			if (nx < 0 || nx > R - 1 || ny < 0 || ny > C - 1) continue;
    			if (A[nx][ny] == 0) continue;
    			if (A[nx][ny] > 0 ) {
    				A[nx][ny] -= 1;
    				if (A[nx][ny] == 0) Q.push({ nx, ny, data.time + 1 });
    			}
    		}
    	}
    	return data.time;
    }
    
    
    
    int main()
    {
    	input();
    	int ans = BFS();
    	printf("%d\n", ans);
    	return 0;
    }
    728x90

    'C 프로그래밍 > BOJ' 카테고리의 다른 글

    [백준 19236] 청소년 상어  (0) 2022.10.24
    [백준 10217] KCM Travel  (0) 2022.10.24
    [백준 2573] 빙산  (0) 2022.10.23
    [백준 3197] 백조의 호수  (0) 2022.10.22
    [백준 5022] 연결  (0) 2022.10.22

    댓글

Designed by Tistory.