https://www.acmicpc.net/problem/14502
최종 풀이
//
// main.cpp
// BJ14502
//
// Created by 최화연 on 2022/04/02.
//
#include <iostream>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
int max_safe_num = 0;
int N, M;
int lab[8][8] = {0, };
int copy_lab[8][8] = {0, };
vector<pair<int, int>> virus;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
void spread_virus(int sy, int sx) {
queue<pair<int, int>> q;
q.push({sx, sy});
while(!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
for(int i=0; i<4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || nx >= M || ny < 0 || ny >= N) continue;
if (copy_lab[ny][nx] == 0) {
copy_lab[ny][nx] = 2;
q.push({nx, ny});
}
}
}
}
int get_safe_area() {
int cnt = 0;
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
if (copy_lab[i][j] == 0) {
cnt ++;
}
}
}
return cnt;
}
void build_walls(int x, int y, int cnt) {
if (cnt == 3) {
memcpy(copy_lab, lab, sizeof(copy_lab));
for(int i=0; i<virus.size(); i++) {
spread_virus(virus[i].first, virus[i].second);
}
int safe_area = get_safe_area();
if (safe_area > max_safe_num) max_safe_num = safe_area;
return;
}
for(int i=y; i<N; i++) {
if(i > y) x = 0;
for(int j=x; j<M; j++) {
if (lab[i][j] == 0) {
lab[i][j] = 1;
build_walls((j+1)%M, i, cnt+1);
lab[i][j] = 0;
}
}
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
cin >> lab[i][j];
if (lab[i][j] == 2) {
virus.push_back({i, j});
}
}
}
build_walls(0, 0, 0);
cout << max_safe_num << endl;
return 0;
}
풀이 과정
풀이 시간 28분
#include <iostream>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
int max_safe_num = 0;
int N, M;
int lab[8][8] = {0, };
int copy_lab[8][8] = {0, };
vector<pair<int, int>> virus;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
void spread_virus(int sy, int sx) {
queue<pair<int, int>> q;
q.push({sx, sy});
while(!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
for(int i=0; i<4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || nx >= M || ny < 0 || ny >= N) continue;
if (copy_lab[ny][nx] == 0) {
copy_lab[ny][nx] = 2;
q.push({nx, ny});
}
}
}
}
int get_safe_area() {
int cnt = 0;
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
if (copy_lab[i][j] == 0) {
cnt ++;
}
}
}
return cnt;
}
void build_walls(int x, int y, int cnt) {
if (cnt == 3) {
memcpy(copy_lab, lab, sizeof(copy_lab));
for(int i=0; i<virus.size(); i++) {
spread_virus(virus[i].first, virus[i].second);
}
int safe_area = get_safe_area();
if (safe_area > max_safe_num) max_safe_num = safe_area;
return;
}
for(int i=y; i<N; i++) {
if(i > y) x = 0;
for(int j=x; j<M; j++) {
if (lab[i][j] == 0) {
lab[i][j] = 1;
build_walls((j+1)%M, i, cnt+1);
lab[i][j] = 0;
}
}
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for(int i=0; i<N; i++) {
for(int j=0; j<M; j++) {
cin >> lab[i][j];
if (lab[i][j] == 2) {
virus.push_back({i, j});
}
}
}
build_walls(0, 0, 0);
cout << max_safe_num << endl;
return 0;
}
이전 풀이
풀이 시간 30분
풀이 1.
//
// main.cpp
// BJ14502
//
// Created by Hwayeon on 2021/07/27.
//
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int N, M;
int map[8][8] = {0,};
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int cmp_map[8][8] = {0,};
int answer = 0;
vector<pair<int, int>> virus;
void copy_map(){
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
cmp_map[i][j] = map[i][j];
}
}
}
void spread_virus(){
//BFS 알고리즘 적용 -> O(V+E) = O(n^2)
//바이러스의 위치들을 queue에 담아준다
queue<pair<int, int>> q;
for(int i=0; i<virus.size(); i++){
q.push(virus[i]);
}
while(!q.empty()){
int x = q.front().first;
int y = q.front().second;
q.pop();
for(int i=0; i<4; i++){
int nx = x+dx[i];
int ny = y+dy[i];
//연구소를 벗어난 경우
if(nx<0 || nx>=M || ny<0 || ny>=N) continue;
//빈칸인 경우 바이러스를 퍼뜨린다
if(cmp_map[ny][nx] == 0){
cmp_map[ny][nx] = 2;
q.push(make_pair(nx, ny));
}
}
}
}
void count_safe_area(){
int safe_area = 0;
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(cmp_map[i][j] == 0) safe_area++;
}
}
if(answer < safe_area) answer = safe_area;
}
void build_wall(int cnt){
//벽을 3개 설치한 경우, 바이러스를 퍼뜨린다
if(cnt == 3){
//퍼뜨리기 전 map의 상태를 보존하기 위해 cmp_map 배열에 복사하여 cmp_map에서 바이러스를 퍼뜨린다
copy_map();
spread_virus();
//안전 영역의 크기를 구한다
count_safe_area();
return;
}
//벽을 설치한다
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(map[i][j] == 0){
map[i][j] = 1;
build_wall(cnt+1);
map[i][j] = 0;
}
}
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
cin >> map[i][j];
if(map[i][j] == 2){
virus.push_back(make_pair(j, i));
}
}
}
build_wall(0);
cout << answer << endl;
return 0;
}
#시간복잡도 = O(n^4), 공간복잡도 = O(n^2)
풀이 2.
풀이 시간 1시간 53분
//
// main.cpp
// BJ14502
//
// Created by Hwayeon on 2021/01/09.
//
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int N,M;
int map[8][8] = {1,};
int map_copy[8][8] = {0,};
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int max_safe_area = 0;
struct location{
int x;
int y;
};
location loc;
vector<location> virus;
void spread_virus(){
queue<location> q;
int safe_area = 0;
for(int i=0; i<virus.size(); i++){
q.push(virus[i]);
}
while(!q.empty()){
int v_x = q.front().x;
int v_y = q.front().y;
q.pop();
for(int d=0; d<4; d++){
int new_x = v_x+dx[d];
int new_y = v_y+dy[d];
if(new_x<0 || new_x>=N || new_y<0 || new_y>=M) continue;
if(map_copy[new_x][new_y] == 0){
map_copy[new_x][new_y] = 2;
loc.x = new_x;
loc.y = new_y;
q.push(loc);
}
}
}
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(map_copy[i][j]==0) safe_area++;
}
}
if(safe_area > max_safe_area) max_safe_area = safe_area;
return;
}
void install_wall(int wall){
if(wall == 3){
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
map_copy[i][j] = map[i][j];
}
}
spread_virus();
return;
}
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(map[i][j] == 0){
map[i][j] = 1;
install_wall(wall+1);
map[i][j] = 0;
}
}
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
cin >> map[i][j];
if(map[i][j] == 0) continue;
else if(map[i][j] == 2){
loc.x = i;
loc.y = j;
virus.push_back(loc);
}
}
}
install_wall(0);
cout << max_safe_area <<endl;
return 0;
}
이 문제는 DFS와 BFS를 활용하여 풀었다. DFS와 BFS에 대한 공부가 필요하다면 글 아래의 참고를 통해 공부하면 된다.
1. 바이러스 위치 저장
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
cin >> map[i][j];
if(map[i][j] == 0) continue;
else if(map[i][j] == 2){
loc.x = i;
loc.y = j;
virus.push_back(loc);
}
}
}
입력값을 받아올 때, 현재 바이러스의 위치를 virus vector에 저장한다.
2. 벽 설치 DFS
void install_wall(int wall){
if(wall == 3){
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
map_copy[i][j] = map[i][j];
}
}
spread_virus();
return;
}
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(map[i][j] == 0){
map[i][j] = 1;
install_wall(wall+1);
map[i][j] = 0;
}
}
}
}
벽이 3개가 설치된 후에 바이러스를 퍼뜨리기 위해 벽 설치를 재귀를 이용한 DFS로 구현했다.
map을 순서대로 탐색하여 빈 칸인 경우, 벽을 설치하고 재귀를 통해 다음 벽을 설치한다. 재귀 함수를 호출한 후에는 벽 3개를 설치하는 모든 경우의 수를 발생시키기 위해 다시 빈 칸으로 되돌려 놓는다.
이렇게 벽 3개가 설치되면, 바이러스를 퍼뜨린다. 이 때, map을 카피한 map_copy에 바이러스를 퍼뜨리도록 한다. (map의 원래 상태를 유지해야 다른 곳에 벽을 설치한 경우에 적용할 수 있다.)
3. 바이러스 퍼뜨리기 BFS
void spread_virus(){
queue<location> q;
int safe_area = 0;
for(int i=0; i<virus.size(); i++){
q.push(virus[i]);
}
while(!q.empty()){
int v_x = q.front().x;
int v_y = q.front().y;
q.pop();
for(int d=0; d<4; d++){
int new_x = v_x+dx[d];
int new_y = v_y+dy[d];
if(new_x<0 || new_x>=N || new_y<0 || new_y>=M) continue;
if(map_copy[new_x][new_y] == 0){
map_copy[new_x][new_y] = 2;
loc.x = new_x;
loc.y = new_y;
q.push(loc);
}
}
}
for(int i=0; i<N; i++){
for(int j=0; j<M; j++){
if(map_copy[i][j]==0) safe_area++;
}
}
if(safe_area > max_safe_area) max_safe_area = safe_area;
return;
}
바이러스는 상,하,좌,우로 퍼지기 때문에 BFS를 활용했다.
1. 바이러스의 위치를 담아주는 q에 입력에서 저장한 최초 바이러스의 위치 vector virus를 담는다.
2. while 반복문
1) q의 pop()하여 바이러스의 위치를 받아온다.
2) 현재 바이러스의 위치에서 상, 하, 좌, 우를 탐색하여 빈 칸인 경우, 바이러스를 퍼뜨리고 q에 새로운 바이러스 위치를 추가한다.
이 과정을 q가 empty일 때까지, 즉, 모든 바이러스를 퍼뜨릴 때까지 반복한다.
3. 안전 영역의 크기를 구하고 max_safe_area와 비교한다.
참고
'코테 노트 > 백준' 카테고리의 다른 글
백준 13460 구슬 탈출 2 C++ (3) | 2021.01.18 |
---|---|
백준 14888 연산자 끼워넣기 C++ (0) | 2021.01.17 |
백준 14890 경사로 C++ (0) | 2021.01.14 |
백준 14503 로봇 청소기 C++ (0) | 2021.01.11 |
백준 14889 스타트와 링크 C++ (0) | 2021.01.06 |