dev_beomgeun
꾸준하게 차근차근
dev_beomgeun
전체 방문자
오늘
어제
  • 분류 전체보기 (170)
    • 전공 (0)
      • 운영체제 (0)
      • 알고리즘 (0)
      • 자료구조 (0)
      • 데이터베이스 (0)
      • 네트워크 (0)
    • 개발 공부 (32)
      • 웹 (6)
      • 리눅스 (4)
      • 머신러닝 (1)
      • 스프링 (17)
      • Git (2)
      • AWS (2)
    • 개발 도서, 강의 (3)
      • 스프링 입문을 위한 자바 객체지향의 원리와 이해 (0)
      • 모든 개발자를 위한 HTTP 웹 기본 지식(김영한.. (2)
      • 스프링 부트와 AWS로 혼자 구현하는 웹서비스 (1)
    • 문제 풀이 (118)
      • 백준 알고리즘 (72)
      • 프로그래머스 알고리즘, SQL (38)
      • Hackerrank SQL (8)
    • 프로젝트 기록 (4)
      • 캡스톤 종합설계 (4)
      • 반려하루 프로젝트 (0)
    • 활동 기록 (12)
      • 네이버 부스트캠프 (7)
      • 취준 & 코테 (4)
      • 소프트웨어 마에스트로 13기 (1)
    • 이것저것 (1)

블로그 메뉴

  • 홈
  • 깃허브
  • 링크드인
  • 방명록

공지사항

인기 글

태그

  • 백준
  • dp
  • 부스트캠프
  • 일기
  • 프로그래머스
  • 그래프탐색
  • 서블릿
  • Hackerrank
  • BFS
  • Baekjoon
  • c++
  • 프로그래머스 SQL
  • 기록
  • AI Tech
  • 백준 DP
  • HackerRank mysql
  • 반성
  • 스프링
  • 회고
  • 네이버 부스트캠프

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
dev_beomgeun

꾸준하게 차근차근

문제 풀이/백준 알고리즘

[baekjoon 14502] 연구소 - 그래프탐색(BFS,DFS), 브루트포스

2020. 12. 5. 20:22
728x90

www.acmicpc.net/problem/14502

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

기본적인 그래프 탐색에 벽을 쌓아야하는 경우를 생각해야하는 문제이다.

처음에 문제를 읽고 무작위 벽 3개를 어떤 로직을 통해 세워야할까, 고민을 하다가 입력값의 최대 배열 크기가 8x8 인것을 보고 브루트포스로 모든 경우를 탐색해보면 되겠다고 생각을 했다.

 

벽을 세우는 케이스는 크게 두가지 인 것 같다.

1. 그래프를 입력받을 때 벽도 없고, 바이러스도 없는 x,y 좌표값을 따로 vector에 보관해두고 이 벡터에서 3가지 경우를 조합해서 벽을 쌓아 탐색하는 경우

2. 백트래킹(재귀)을 이용해서 조합 알고리즘으로 3개의 벽을 쌓아 탐색하는 경우

 

나의 경우 1번을 통해 3중for문을 통해 벽을 세웠다.

 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

int N, M, num, wall, check[9][9], range[9][9], Max, disX[4] = { 1,-1,0,0 }, disY[4] = { 0, 0, 1, -1 };
vector < pair<int, int>> virus;
vector < pair<int, int>> noWall;

void VirusBFS(int x, int y) {
	queue<pair<int, int>> q;
	q.push(make_pair(x, y));

	while (!q.empty()) {
		int tempX = q.front().first;
		int tempY = q.front().second;
		check[tempX][tempY] = 1;
		q.pop();

		for (int i = 0; i < 4; i++) {
			int X = tempX + disX[i];
			int Y = tempY + disY[i];
			if (X >= 0 && X < N && Y >= 0 && Y < M) {
				if (!check[X][Y] && range[X][Y] == 0) {
					check[X][Y] = 1;
					q.push(make_pair(X, Y));
				}
			}
		}
	}
}

void clearCheck() {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			check[i][j] = 0;
		}
	}
}

int main() {
	ios::sync_with_stdio(false); cin.tie(NULL);
	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> num;
			range[i][j] = num;
			if (num == 0) {
				noWall.push_back(make_pair(i, j));
			}
			else if (num == 2)
				virus.push_back(make_pair(i, j));
		}
	}
	int noWallSize = noWall.size();
	for (int i = 0; i < noWallSize-2; i++) {
		pair<int, int> temp1 = noWall[i];
		range[temp1.first][temp1.second] = 1;
		// 1차 벽 세우기
		for (int j = i + 1; j < noWallSize-1; j++) {
			pair<int, int> temp2 = noWall[j];
			range[temp2.first][temp2.second] = 1;
			// 2차 벽세우기
			for (int k = j + 1; k < noWallSize; k++) {
				pair<int, int> temp3 = noWall[k];
				range[temp3.first][temp3.second] = 1;
				// 3차 벽세우기
				for (int vir = 0; vir < virus.size(); vir++) {
					VirusBFS(virus[vir].first, virus[vir].second);
					// 벽 세우고 Virus 퍼진 상태
				}
				int cnt = 0;
				for (int Xx = 0; Xx < N; Xx++) {
					for (int Yy = 0; Yy < M; Yy++) {
						if (range[Xx][Yy] == 0 && !check[Xx][Yy]){
							cnt++;
							Max = max(Max, cnt);
						}
					}
				}
				clearCheck();
				range[temp3.first][temp3.second] = 0;
				//계속 세번째 벽 위치만 바뀌므로 세번째만 해제해준다.
			}
			range[temp2.first][temp2.second] = 0;
			// 세번째 모두 돌면 두번째 벽 바꿔줘야하므로 해제해준다.
		}
		range[temp1.first][temp1.second] = 0;
		// 첫번째 벽 해제
	}

	cout << Max;
}

3중 for문을 시작하는 부분부터 0만 저장되어 있는 좌표에서 하나씩 꺼내서 벽을 세워준다.

그리고 각자의 for문이 끝나면 원래의 입력받은 그래프로 바꾸기 위해서 0으로 다시 바꿔준다.

3중 for문으로 벽을 다 세운 다음엔 virus 벡터에서 2인 케이스를 시작점으로 그래프탐색을 해준다.

나는 바이러스가 퍼진 경우를 지도에 직접 바꾸기보다 check (방문여부 2차원 배열)을 바꿔줌으로써 나중에 안전영역의 갯수를 셀때 구별을 해주었다.

그렇게 바이러스가 퍼질 수 있는 탐색을 모두 마친 후, 0이면서 방문하지 않은 위치의 갯수를 세서 최댓값을 max에 저장 후 출력해주었다.

 

- 피드백

1. for문을 많이 쓰다 보니까 for문 안의 변수를 다른 for문의 변수로 잘못 쓴 경우가 빈번했다.

이 경우 for문의 변수가 제대로 실행되지 않아서 runtime error가 발생했다. 

 

2. 문제를 제대로 읽자. -> 처음에 connected component처럼 0이 이어져있는 최대의 영역을 구하는 건 줄 알고 0을 구하기 위해서 BFS를 한번 더 탐색했고, 답도 틀리게 나왔다.

이 문제에서는 그냥 최종적으로 탐색 후 0의 갯수만 세면 되는 것이었다.

728x90

'문제 풀이 > 백준 알고리즘' 카테고리의 다른 글

[baekjoon 17269] 이름궁합 테스트- 문자열, 구현 (C++)  (0) 2020.12.27
[baekjoon 14425] 문자열 집합- 문자열, map (C++)  (0) 2020.12.24
[baekjoon 1922] 네트워크 연결 - 최소 스패닝 트리(크루스칼, Union-Find)  (0) 2020.11.29
[baekjoon 2468] 안전영역 - 그래프탐색(BFS, DFS)  (0) 2020.11.24
[baekjoon 14438] 수열과 쿼리 17 - 세그먼트 트리  (0) 2020.11.20
    '문제 풀이/백준 알고리즘' 카테고리의 다른 글
    • [baekjoon 17269] 이름궁합 테스트- 문자열, 구현 (C++)
    • [baekjoon 14425] 문자열 집합- 문자열, map (C++)
    • [baekjoon 1922] 네트워크 연결 - 최소 스패닝 트리(크루스칼, Union-Find)
    • [baekjoon 2468] 안전영역 - 그래프탐색(BFS, DFS)
    dev_beomgeun
    dev_beomgeun
    백엔드 개발을 하며 얻은 지식과 경험을 공유합니다. 현재 카카오페이에서 백엔드 엔지니어로 일하고 있습니다.

    티스토리툴바