BOJ 16946. 벽 부수고 이동하기 4
🙇♀️[Gold II] 벽 부수고 이동하기 4 - 16946
성능 요약
메모리: 17004 KB, 시간: 140 ms
분류
너비 우선 탐색, 깊이 우선 탐색, 그래프 이론, 그래프 탐색
제출 일자
2024년 3월 1일 14:32:31
문제 설명
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 한 칸에서 다른 칸으로 이동하려면, 두 칸이 인접해야 한다. 두 칸이 변을 공유할 때, 인접하다고 한다.
각각의 벽에 대해서 다음을 구해보려고 한다.
- 벽을 부수고 이동할 수 있는 곳으로 변경한다.
- 그 위치에서 이동할 수 있는 칸의 개수를 세어본다.
한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.
입력
첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다.
출력
맵의 형태로 정답을 출력한다. 원래 빈 칸인 곳은 0을 출력하고, 벽인 곳은 이동할 수 있는 칸의 개수를 10으로 나눈 나머지를 출력한다.
🚀풀이
이 문제를 처음에 도전할 때는 문제의 조건의 순서대로 해결하려고 했다.
벽 위치에서 BFS를 돌려서 0의 개수를 세고 출력하는 방식이였는데 시간초과가 났다.
다른 방식을 이용해야하는데 0의 개수를 미리 세어 놓고 벽을 부술 때 상하좌우를 체크하여 0들을 한꺼번에 계산하는 방식이다.
이 때 중복된 영역인지 아닌지 알기 위해서 0들의 영역당 인덱스를 붙여야한다.
그 인덱스를 zeroAreaIdx
로 이름지었고, 0들의 영역은 zeroArea
로 지었다.
zeroArea
는 값으로 인덱스만 가지고 있다. 실제로 0의 개수는 zeroAreaZeroCount
란 이름으로 계산한다.
BFS를 돌릴 때 위의 변수들을 주의해서 보자.
그리고 다른 사람들은 나중에 1인 벽인 공간에서 상하좌우를 계한할 때 다 set을 이용했는데 며칠걸린 이 문제를 그냥 다른사람처럼 풀기 싫었다. (그냥 미련한 바보임)
난 그냥 set을 안쓰고 계산해서 체크했다.
아무튼 맞았으면 된거지 ㅇㅅㅇ
🚀전체 코드
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include<iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
// 시간초과가 뜨지 않게 변환
int n, m, zeroAreaIdx = 0;
int dy[] = { -1, 0, 1, 0 };
int dx[] = { 0, 1, 0, -1 };
int board[1111][1111];
int zeroArea[1111][1111];
int visited[1111][1111];
vector<int> zeroAreaZeroCount;
int BFS(int y, int x)
{
int res = 0;
queue<pair<int, int>> q;
q.push({ y, x });
visited[y][x] = 1;
zeroArea[y][x] = zeroAreaIdx;
pair<int, int> here;
while (q.empty() == false)
{
here = q.front();
q.pop();
res++;
for (int i = 0; i < 4; ++i)
{
int ny = here.first + dy[i];
int nx = here.second + dx[i];
if (ny < 1 || nx < 1 || ny > n || nx > m)
continue;
if (visited[ny][nx] == 1)
continue;
if (board[ny][nx] == 1)
continue;
q.push({ ny, nx });
visited[ny][nx] = 1;
zeroArea[ny][nx] = zeroAreaIdx;
}
}
zeroAreaZeroCount.push_back(res);
return res % 10;
}
void solve()
{
// 입력값 받기
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
string str;
cin >> str;
for (int j = 1; j <= m; ++j)
{
board[i][j] = str[j - 1] - '0';
}
}
// 0번 인덱스랑 곂치니까 -1로 초기화
::memset(zeroArea, -1, sizeof(zeroArea));
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (board[i][j] == 0 && visited[i][j] == 0)
{
BFS(i, j);
// 인덱스 증가 시켜서 다른 그룹으로 만들기
zeroAreaIdx++;
}
}
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (board[i][j] == 1)
{
vector<int> cache(4, -1);
for (int k = 0; k < 4; ++k)
{
int ny = i + dy[k];
int nx = j + dx[k];
cache[k] = zeroArea[ny][nx];
}
sort(cache.begin(), cache.end());
cache.push_back(-1);
int res = 0;
for (int k = 0; k < 4; ++k)
{
if (cache[k] == -1)
continue;
if (cache[k] == cache[k + 1])
continue;
res += zeroAreaZeroCount[cache[k]];
}
::cout << (res + 1) % 10;
}
else
::cout << 0;
}
::cout << '\n';
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
::cout.tie(NULL);
freopen("input.txt", "rt", stdin);
solve();
return 0;
}