https://www.acmicpc.net/problem/2234
2234번: 성곽
문제 대략 위의 그림과 같이 생긴 성곽이 있다. 굵은 선은 벽을 나타내고, 점선은 벽이 없어서 지나다닐 수 있는 통로를 나타낸다. 이러한 형태의 성의 지도를 입력받아서 다음을 계산하는 프로그램을 작성하시오. 이 성에 있는 방의 개수 가장 넓은 방의 넓이 하나의 벽을 제거하여 얻을 수 있는 가장 넓은 방의 크기 위의 예에서는 방은 5개고, 가장 큰 방은 9개의 칸으로 이루어져 있으며, 위의 그림에서 화살표가 가리키는 벽을 제거하면 16인 크기의 방을 얻을
www.acmicpc.net
bfs를 이용하여 푼 문제이다. 문제에서 이진수를 이용하여 풀라고 힌트를 주었다.
우선 10진수로 입력 받은 수를 네 자리 이진수로 바꾸어 저장한다. 예를 들어 11이면 1011로 바꾼다는 것이다. 이렇게 바꾼 이진수를 이용하여 1과 0의 위치로 동서남북에 벽이 있는지 찾는다. 네 자리가 나타내는 방향은 남동북서이다.
각각의 숫자를 입력 받으면 특정 방에 속하는 칸인지 체크하여 방을 찾는다. bfs를 이용하여 찾고 탐색하는 과정에서 각 방에 속하는 칸인지 세어 특정 변수에 저장한다. bfs를 사용할 때 네 자리수를 각각 한 자리씩 0인지 1인지 비교하여 4방향으로 탐색을 진행한다. 0이면 탐색하고 1이면 탐색하지 않는다.
가장 많은 칸을 차지하는 방은 반복문을 이용하여 탐색하였다. bfs를 이용하여 각 방마다 차지하는 칸의 수를 저장한 공간을 탐색한다.
벽을 부수는 작업은 이중포문을 이용하여 풀었다. 각각의 칸에서 4방향으로 현재 있는 칸과 서로 다른 방에 있는 칸인지 비교하여 다르다면 더하는 작업을 통해서 가장 큰 수를 찾았다.
#include <iostream>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#define MAX 51
using namespace std;
int m, n; //가로, 세로
int num; //각 칸의 숫자
int big = -1; //벽을 부수기 전에 가장 큰 넓이
int plus_big = -1; //벽을 부수고 난 후에 가장 큰 넓이
int cnt = 1; //방의 갯수
int d[MAX][MAX] = { 0, }; //각 공간을 탐색한 여부
string mat[MAX][MAX]; //각 칸의 숫자를 이진수로 바꾼 결과를 저장
vector<int> area; //각 방의 넓이를 순서대로 저장
//네 자리 이진수 만들기
string change(int num) {
string check;
int len;
while (num) {
char temp;
temp = char('0' + num % 2);
num = num / 2;
check = temp + check;
}
len = check.size();
for (int i = 0; i < 4 - len; i++) {
check = '0' + check;
}
return check;
}
void bfs(int x, int y) {
int res = 1; //현재 탐색하는 곳에 면적
queue<pair<int, int>> q;
q.push(pair<int, int>(x, y));
d[x][y] = cnt;
while (!q.empty()) {
x = q.front().first;
y = q.front().second;
q.pop();
//동서남북으로 벽이 있는지 조사하고 벽이 없으면 탐색한다.
//탐색할 때 면적을 한 개씩 늘려서 탐색하고 최종적으로 구한 면적을 벡터에 넣는다.
//탐색할 때 방의 방문 여부는 방의 순서로 기록해 놓아서 bool대신 int를 이용하였다.
if (mat[x][y][3] == '0') { //west
if (1 <= x && x <= n && 1 <= y - 1 && y - 1 <= m && !d[x][y - 1]) {
q.push(pair<int, int>(x, y - 1));
res++;
d[x][y - 1] = cnt;
}
}
if (mat[x][y][2] == '0') { //north
if (1 <= x - 1 && x - 1 <= n && 1 <= y && y <= m && !d[x - 1][y]) {
q.push(pair<int, int>(x - 1, y));
res++;
d[x - 1][y] = cnt;
}
}
if (mat[x][y][1] == '0') { //east
if (1 <= x && x <= n && 1 <= y + 1 && y + 1 <= m && !d[x][y + 1]) {
q.push(pair<int, int>(x, y + 1));
res++;
d[x][y + 1] = cnt;
}
}
if (mat[x][y][0] == '0') { //south
if (1 <= x + 1 && x + 1 <= n && 1 <= y && y <= m && !d[x + 1][y]) {
q.push(pair<int, int>(x + 1, y));
res++;
d[x + 1][y] = cnt;
}
}
}
area.push_back(res);
}
int main() {
cin >> m >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> num; //칸에 대한 숫자 입력
mat[i][j] = change(num); //칸에 대한 숫자를 이진수로 변경하여 저장
}
}
area.push_back(0); //1번 방부터 시작이여서 0번지를 0으로 채워 놓음
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (!d[i][j]) { //탐색을 안한 칸이면
bfs(i, j); //같은 방에 있는 칸을 찾아 탐색
cnt++; //방에 갯수 증가
}
}
}
//현재 주어진 방 들중 가장 많은 칸을 차지하는 방을 찾음
for (int i = 1; i < area.size(); i++) {
big = max(big, area[i]);
}
//벽 하나 부수기
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (1 <= i - 1 && i - 1 <= n && 1 <= j && j <= m && d[i - 1][j] != 0 && d[i - 1][j] != d[i][j]) { //유효 범위이고 위에 방이 존재하고 현재 방과 다른 방이면
plus_big = max(plus_big, area[d[i][j]] + area[d[i - 1][j]]); //현재 벽 부수기 vs 이전 벽 부수기로 큰 값 찾음
}
if (1 <= i + 1 && i + 1 <= n && 1 <= j && j <= m && d[i + 1][j] != 0 && d[i + 1][j] != d[i][j]) { //유효 범위이고 아래에 방이 존재하고 현재 방과 다른 방이면
plus_big = max(plus_big, area[d[i][j]] + area[d[i + 1][j]]); //현재 벽 부수기 vs 이전 벽 부수기로 큰 값 찾음
}
if (1 <= i && i <= n && 1 <= j - 1 && j - 1 <= m && d[i][j - 1] != 0 && d[i][j - 1] != d[i][j]) { //유효 범위이고 왼쪽에 방이 존재하고 현재 방과 다른 방이면
plus_big = max(plus_big, area[d[i][j]] + area[d[i][j - 1]]); //현재 벽 부수기 vs 이전 벽 부수기로 큰 값 찾음
}
if (1 <= i && i <= n && 1 <= j + 1 && j + 1 <= m && d[i][j + 1] != 0 && d[i][j + 1] != d[i][j]) { //유효 범위이고 오른쪽에 방이 존재하고 현재 방과 다른 방이면
plus_big = max(plus_big, area[d[i][j]] + area[d[i][j + 1]]); //현재 벽 부수기 vs 이전 벽 부수기로 큰 값 찾음
}
}
}
cout << cnt - 1 << '\n';
cout << big << '\n';
cout << plus_big;
}
'백준' 카테고리의 다른 글
백준1600 - 말이 되고픈 원숭이 (0) | 2020.03.13 |
---|---|
백준17141 - 연구소 2 (0) | 2020.03.12 |
백준10819 - 차이를 최대로 (0) | 2020.03.10 |
백준1967 - 트리의 지름 (0) | 2020.03.10 |
백준7569 - 토마토 (0) | 2020.03.05 |