새소식

코딩테스트/백준_골드

[C++][백준 14502] 연구소

  • -

[문제]

14502번: 연구소 (acmicpc.net)

 

14502번: 연구소

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

www.acmicpc.net

[문제 풀이]

n * m의 공간인 연구소에 바이러스가 퍼졌다. 2인 칸에서 부터 바이러스는 퍼지고 벽(1)의 부딪히거나 범위에 부딪히면 더 이상 퍼지지 못한다. 3개의 벽을 추가로 건설해서 바이러스를 최대한 덜 퍼트펴보자.

 

벽은 무조건 3개이고 0인 곳에 세울 수 있다.

그러니 0인 칸의 모든 좌표값을 알고 있을 때 이 중 3가지를 뽑아서 나올 수 있는 경우의 수가 문제에서 요구하는 거라고 봐도 무방할 것이다.

백준 n과 m 시리즈에서 자주 접했던 문제 즉, 0의 모든 좌표 (n) 에서 3개의 좌표(m)을 뽑아보자.

void backTrack(int cnt){ if(loc.size() == 3){ return; } for(int i = cnt;i<vec.size();i++){ if(visited[vec[i].first][vec[i].second] == 0){ visited[vec[i].first][vec[i].second] = 1; loc.push_back(vec[i]); backTrack(cnt + 1); loc.pop_back(); visited[vec[i].first][vec[i].second] = 0; } } return; }

 

중복좌표를 만들지 않기 위하여 visited 처리와 loc이라는 벡터에 해당 위치를 넣고 빼고를 반복하면서 백트래킹을 해주었다.

 

이제 loc의 크기가 3 즉, 3개의 벽이 설치되었다면 bfs를 이용해서 2가 총 몇번을 갈 수 있는지 파악을 하자.

 

bool inRange(int x, int y){ if(x >= 0 && x < n && y >= 0 && y < m){ return true; } return false; } int bfs(){ for(int i = 0;i<n;i++){ for(int j = 0;j<m;j++){ viurs_visited[i][j] = 0; } } //answer는 0의 숫자를 세는 변수. oneNum은 이미 세워져있는 벽의 숫자. int answer = n * m - oneNum - 3; for(int i = 0;i<loc.size();i++){ arr[loc[i].first][loc[i].second] = 1; } queue<pair<int,int> > q; for(int i = 0;i<virus.size();i++){ q.push(virus[i]); viurs_visited[virus[i].first][virus[i].second] = 1; answer--; } while(q.size() > 0){ int curX = q.front().first; int curY = q.front().second; q.pop(); for(int i = 0;i<4;i++){ int nextX = curX + dx[i]; int nextY = curY + dy[i]; if(inRange(nextX,nextY) == true && viurs_visited[nextX][nextY] == 0){ //벽이 아니라면 if(arr[nextX][nextY] == 0){ viurs_visited[nextX][nextY] = 1; q.push(make_pair(nextX,nextY)); answer--; } } } } for(int i = 0;i<loc.size();i++){ arr[loc[i].first][loc[i].second] = 0; } return answer; }

 

이와 같은 bfs를 통해서 우리들은 0의 좌표를 알 수가 있다.

bfs + 백트래킹 문제가 처음이면 어려울만 하지만 골드5를 넘어서는 bfs의 경우에는 조건이 추가되어 있거나 bfs + 이분탐색, 백트래킹 등으로 조건을 주는 경우가 많다. 처음에는 어려울 수 있지만 풀다보면 익숙해지니 양치기를 해보자.

[회고]

테스트 케이스가 좋아서 특별히 어려운 점은 없었다.

[코드]

#include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; int n,m; int answer; int oneNum; int arr[10][10]; int visited[10][10]; int viurs_visited[10][10]; int max_answer; int dx[4] = {1,0,-1,0}; int dy[4] = {0,1,0,-1}; vector<pair<int,int> > vec; vector<pair<int,int> > loc; vector<pair<int,int> > virus; bool inRange(int x, int y){ if(x >= 0 && x < n && y >= 0 && y < m){ return true; } return false; } int bfs(){ for(int i = 0;i<n;i++){ for(int j = 0;j<m;j++){ viurs_visited[i][j] = 0; } } int answer = n * m - oneNum - 3; for(int i = 0;i<loc.size();i++){ arr[loc[i].first][loc[i].second] = 1; } queue<pair<int,int> > q; for(int i = 0;i<virus.size();i++){ q.push(virus[i]); viurs_visited[virus[i].first][virus[i].second] = 1; answer--; } while(q.size() > 0){ int curX = q.front().first; int curY = q.front().second; q.pop(); for(int i = 0;i<4;i++){ int nextX = curX + dx[i]; int nextY = curY + dy[i]; if(inRange(nextX,nextY) == true && viurs_visited[nextX][nextY] == 0){ //벽이 아니라면 if(arr[nextX][nextY] == 0){ viurs_visited[nextX][nextY] = 1; q.push(make_pair(nextX,nextY)); answer--; } } } } for(int i = 0;i<loc.size();i++){ arr[loc[i].first][loc[i].second] = 0; } return answer; } void backTrack(int cnt){ if(loc.size() == 3){ if(max_answer < bfs()){ max_answer = bfs(); } return; } for(int i = cnt;i<vec.size();i++){ if(visited[vec[i].first][vec[i].second] == 0){ visited[vec[i].first][vec[i].second] = 1; loc.push_back(vec[i]); backTrack(cnt + 1); loc.pop_back(); visited[vec[i].first][vec[i].second] = 0; } } return; } int main(){ cin>>n>>m; for(int i = 0;i<n;i++){ for(int j = 0;j<m;j++){ cin>>arr[i][j]; if(arr[i][j] == 0){ vec.push_back(make_pair(i,j)); } else if(arr[i][j] == 2){ virus.push_back(make_pair(i,j)); } else if(arr[i][j] == 1){ oneNum++; } } } backTrack(0); cout<<max_answer<<endl; return 0; }

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.