728x90
문제
https://www.acmicpc.net/problem/16946
풀이 방법
벽을 부쉈을 때 이동할 수 있는 칸의 갯수를 구하면 되는 문제다.
단, 모든 벽마다 탐색을 해서 이동할 수 있는 칸 개수를 구하면 시간 초과가 발생한다. 예를 들어 다음과 같은 케이스가 들어온다고 해보자.
예시:
6 6
101010
000000
101010
000000
101010
000000
1에서 탐색을 시작할때마다 모든 0의 개수를 반복적으로 구하기 때문에 시간복잡도가 O(N^2 M^2)인 것을 알 수 있다. 따라서 다른 방법으로 풀어야한다.
0에서 탐색을 시작해 인접한 0의 개수를 구하고, 구하는 과정에서 벽을 만날 경우 그 벽의 좌표를 저장해놓는다. 탐색 종료 후 저장된 벽들에 인접한 0의 개수를 더해주면, 결국 벽에 연결되어 있는 0의 개수가 저장된다.
코드
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int dy[] = {-1,0,0,1};
int dx[] = {0,-1,1,0};
void bfs(vector<vector<int>> &v, vector<vector<bool>> &visited, int y, int x)
{
vector<pair<int, int>> walls;
queue<pair<int,int>> q;
q.push({y,x});
visited[y][x] = true;
int count = 1;
while(!q.empty())
{
int curY = q.front().first;
int curX = q.front().second;
q.pop();
for(int i=0; i<4; i++)
{
int ny = curY + dy[i];
int nx = curX + dx[i];
if(ny < 0 || ny >= v.size() || nx < 0 || nx >= v[0].size()) continue;
if(visited[ny][nx]) continue;
if(v[ny][nx])
{
visited[ny][nx] = true;
walls.push_back({ny, nx});
}
else
{
count++;
q.push({ny,nx});
visited[ny][nx] = true;
}
}
}
for(int i=0; i<walls.size(); i++)
{
v[walls[i].first][walls[i].second] += count;
visited[walls[i].first][walls[i].second] = false;
}
}
int main()
{
int N, M;
scanf("%d %d", &N, &M);
vector<vector<int>> v(N, vector<int>(M, false));
vector<vector<bool>> visited(N, vector<bool>(M, false));
for(int i=0; i<N; i++)
{
for(int j=0; j<M; j++)
{
int t;
scanf("%1d", &t);
v[i][j] = t;
}
}
for(int i=0; i<N; i++)
{
for(int j=0; j<M; j++)
{
if(!v[i][j] && !visited[i][j])
{
bfs(v, visited, i, j);
}
}
}
for(int i=0; i<N; i++)
{
for(int j=0; j<M; j++)
{
printf("%d", v[i][j] % 10);
}
printf("\n");
}
return 0;
}
고찰
위의 예시 케이스를 생각못해서 처음엔 모든 벽에 대해 다 탐색을 돌렸다가 시간초과가 발생했다.
728x90