https://www.acmicpc.net/problem/16946
16946번: 벽 부수고 이동하기 4
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이
www.acmicpc.net
벽 부수고 이동하기 시리즈 마지막 문제
접근 방법
이 문제는 1.2.3 번 문제의 코드와 연관이 없는 문제다. 특정 벽을 부술 때 연결된 칸 수를 구한다.
가장 먼저 떠오르는 풀이는 모든 벽을 부숴보고 bfs/dfs를 돌리는건데, K개의 벽이 있다고 할 때 시간 복잡도가 O(NMK)가 될 것이 자명하므로 시도하지 않는다.
bfs/dfs를 최소한으로 사용하는 경우를 생각 해 보니, N*M의 맵에서 dfs/bfs를 이용하여 존재하는 공간에 대해서 크기를 미리 계산한다. 그리고 모든 벽에 대해서, 벽을 부숨으로 인해 생기는 4방향의 크기만 더해주면 될 것 같았다. 그렇게 하면 O(c*NM) 시간 안에 해결이 된다. 아마 c는 8?
벽을 부수기 전 dfs 전처리를 할 때,
1. N*M 크기의 새로운 배열에 해당 칸의 계산된 크기(dfs를 하여 나온 크기를 해당하는 칸에 모두 저장)를 저장하는 방법과
2. dfs를 하여 계산된 크기를 (index - cnt)으로 벡터에 따로 저장하고, N*M 크기의 새로운 배열에 해당 칸의 index로만 채우는 방법
두 가지를 고민했다. 1번 방법은 dfs를 두 번 돌려야 해서 코드가 길어질 것 같아서 포기하고, 2번 방법으로 접근했다. 결론적으로 4방향을 조사할 때 같은 공간인 경우 한번만 더해주어야 하는데, 이 때 c++의 set 라이브러리를 사용하여 index값을 저장하여 효과적으로 해결해서 좋은 선택이 되었다.
풀이
tag : bfs/dfs
#include<iostream>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
int N,M;
int arr[1001][1001];
int idx=0;
vector<int> cntVector;
int cnt=0;
int visited[1001][1001]={0};
int idxArr[1001][1001];
const int dy[4]={-1,0,1,0};
const int dx[4]={0,1,0,-1};
int dfs(int r,int c,int idx){ //빈칸인곳들 크기 계산 // 센 개수 반환
cnt++;
idxArr[r][c]=idx;
visited[r][c]=1;
for(int i=0;i<4;i++){
int nr=r+dy[i];
int nc=c+dx[i];
if(nr<0 || nc<0 || nr>=N || nc >=M)
continue;
if(arr[nr][nc]==0 && visited[nr][nc]==0)
dfs(nr,nc,idx);
}
return cnt;
}
int main(){
memset(idxArr,-1,sizeof(idxArr));
cin>>N>>M;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
scanf("%1d",&arr[i][j]);
}
}
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
if(visited[i][j]==0 && arr[i][j]==0){
cnt=0;
int tmp=dfs(i,j,idx++);
cntVector.push_back(tmp);
}
}
}
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
int sum=0;
if(arr[i][j]==1){ //벽이면 부수자
set<int> set; //중복제거
sum+=1;
for(int k=0;k<4;k++){
int nr=i+dy[k];
int nc=j+dx[k];
if(nr<0 || nc<0 || nr>=N || nc >=M || arr[nr][nc]==1)
continue;
set.insert(idxArr[nr][nc]);
}
for(int i : set){
sum+=cntVector[i];
}
}
printf("%d",sum%10);
}
printf("\n");
}
}
코드를 간결하게 짜는데 중점을 두면, 전역변수를 많이 사용하게 되는데, 좋은건지 나쁜건지 모르겠다
'Algorithm > BOJ' 카테고리의 다른 글
[백준/BOJ] 9019 DSLR - 접근과 풀이 (c++) (1) | 2022.09.16 |
---|---|
[백준/BOJ] 2580 스도쿠 - 접근과 풀이 (c++) (0) | 2022.09.16 |
[백준/BOJ] 16933 벽 부수고 이동하기 3 - 접근과 풀이 (c++) (0) | 2022.09.13 |
[백준/BOJ] 14442 벽 부수고 이동하기 2 - 접근과 풀이 (c++) (0) | 2022.09.13 |
[백준/BOJ] 2206 벽 부수고 이동하기 - 접근과 풀이 (c++) (0) | 2022.09.13 |