Algorithm
[BOJ] 14502번 : 연구소
rudgh99_algo
2024. 8. 24. 14:10
1. problem :
https://www.acmicpc.net/problem/14502
2. solution 1 :
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
int n, m;
int board[10][10]; //400byte 원본
int board2[10][10]; // 400byte 사본 -> 자유롭게 수정가능
int dx[4] = { 0,1,0,-1 };
int dy[4] = { 1,0,-1,0 };
vector<pair<int, int>> viruse;
vector<int> wall;
int ans;
void bfs() {
queue<pair<int, int>> Q;
for (auto v : viruse) {
Q.push({ v.X,v.Y });
}
while (!Q.empty()) {
auto cur = Q.front(); Q.pop();
for (int dir = 0; dir < 4; dir++) {
int nx = cur.X + dx[dir];
int ny = cur.Y + dy[dir];
if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if ( board2[nx][ny] == 2 || board2[nx][ny] == 1) continue;
board2[nx][ny] = 2;
Q.push({ nx,ny });
}
}
}
void safe_zone_cnt() {
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board2[i][j] == 0) cnt++;
}
}
ans = max(ans, cnt);
}
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> board[i][j];
if (board[i][j] == 2) viruse.push_back({ i,j });
board2[i][j] = board[i][j];
}
}
wall.resize(n * m); // 벽 벡터 크기 조정
fill(wall.begin() + n * m - 3, wall.begin() + n*m, 1);
do {
bool isdup = false;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) board2[i][j] = board[i][j];
}
vector<pair<int, int>> wall_xy;
for (int i = 0; i < n*m; i++) {
if (wall[i] == 1) {
int x = i / m;
int y = i % m;
if (board2[x][y] != 0) {
isdup = true;
break;
}
wall_xy.push_back({ x,y });
}
}
if (!isdup) {
for (auto s : wall_xy) {
board2[s.X][s.Y] = 1;
}
// bfs 실행
bfs();
safe_zone_cnt();
}
} while (next_permutation(wall.begin(), wall.end()));
cout << ans;
}
3. solution 2 :
// Authored by : BaaaaaaaaaaarkingDog
// Co-authored by : jihwan0123
// http://boj.kr/b4a6eb773dd245e88475502d0b25d168
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
int board[8][8];
int n, m, ans;
int free_cells = 0;
queue<pair<int, int>> virus; // 바이러스
vector<pair<int, int>> frees; // 빈칸
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// 바이러스가 전파된 칸의 수를 반환
int bfs() {
queue<pair<int, int>> q;
bool vis[8][8] = {};
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(board[i][j] == 2) q.push({i, j});
}
}
int ret = 0;
while (!q.empty()) {
pair<int, int> cur = q.front();
q.pop();
ret++;
for (int i = 0; i < 4; i++) {
int nx = cur.X + dx[i];
int ny = cur.Y + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (board[nx][ny] != 0 || vis[nx][ny]) continue;
vis[nx][ny] = 1;
q.push({nx, ny});
}
}
return ret;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> board[i][j];
if (board[i][j] == 0) { // 빈 칸 개수와 좌표 저장
free_cells++;
frees.push_back({i, j});
} else if (board[i][j] == 2) // 바이러스 좌표 저장
virus.push({i, j});
}
}
for(int i = 0; i < frees.size(); i++){
board[frees[i].X][frees[i].Y] = 1;
for(int j = i + 1; j < frees.size(); j++){
board[frees[j].X][frees[j].Y] = 1;
for(int k = j + 1; k < frees.size(); k++){
board[frees[k].X][frees[k].Y] = 1;
// 바이러스 퍼진 개수 체크
int tmp = bfs();
// 안전영역 = 빈칸 - 바이러스 퍼진 칸, 3을 빼는 이유는 벽을 3개 세웠으므로.
ans = max(free_cells - 3 - tmp + (int)virus.size(), ans);
board[frees[k].X][frees[k].Y] = 0;
}
board[frees[j].X][frees[j].Y] = 0;
}
board[frees[i].X][frees[i].Y] = 0;
}
cout << ans;
}
/*
3중 for문을 이용해 빈칸 중에서 3개씩 벽으로 바꿔보면서 최대 크기 계산
*/
source code 출처 : https://github.com/encrypted-def/basic-algo-lecture/blob/master/0x0D/solutions/14502.cpp
basic-algo-lecture/0x0D/solutions/14502.cpp at master · encrypted-def/basic-algo-lecture
바킹독의 실전 알고리즘 강의 자료. Contribute to encrypted-def/basic-algo-lecture development by creating an account on GitHub.
github.com
4. solution 3 :
// Authored by : jihwan0123
// Co-authored by : BaaaaaaaaaaarkingDog
// http://boj.kr/c7974a009076431aaebdf25b5792144f
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
int board[8][8];
int n, m, ans;
int free_cells = 0;
queue<pair<int, int>> virus; // 바이러스
vector<pair<int, int>> frees; // 빈칸
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// 바이러스가 전파된 칸의 수를 반환
int bfs() {
queue<pair<int, int>> q;
bool vis[8][8] = {};
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(board[i][j] == 2) q.push({i, j});
}
}
int ret = 0;
while (!q.empty()) {
pair<int, int> cur = q.front();
q.pop();
ret++;
for (int i = 0; i < 4; i++) {
int nx = cur.X + dx[i];
int ny = cur.Y + dy[i];
if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if (board[nx][ny] != 0 || vis[nx][ny]) continue;
vis[nx][ny] = 1;
q.push({nx, ny});
}
}
return ret;
}
// k번째 벽의 위치를 선택, idx번째 빈 칸부터 고려
void dfs(int k, int idx) {
// 벽 3개 세웠으면 bfs로 확인
if (k == 3) {
// 바이러스 퍼진 개수 체크
int tmp = bfs();
// 안전영역 = 빈칸 - 바이러스 퍼진 칸, 3을 빼는 이유는 벽을 3개 세웠으므로.
ans = max(free_cells - 3 - tmp + (int)virus.size(), ans);
return;
}
// 각 빈 칸을 벽으로 변경해서 백트래킹 진행
for (int i = idx; i < frees.size(); i++) {
board[frees[i].X][frees[i].Y] = 1;
dfs(k + 1, i + 1);
board[frees[i].X][frees[i].Y] = 0;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> board[i][j];
if (board[i][j] == 0) { // 빈 칸 개수와 좌표 저장
free_cells++;
frees.push_back({i, j});
} else if (board[i][j] == 2) // 바이러스 좌표 저장
virus.push({i, j});
}
}
dfs(0, 0);
cout << ans;
}
/*
백트래킹을 이용해 빈칸 중에서 3개씩 벽으로 바꿔보면서 최대 크기 계산
*/
https://github.com/encrypted-def/basic-algo-lecture/blob/master/0x0D/solutions/14502_1.cpp
basic-algo-lecture/0x0D/solutions/14502_1.cpp at master · encrypted-def/basic-algo-lecture
바킹독의 실전 알고리즘 강의 자료. Contribute to encrypted-def/basic-algo-lecture development by creating an account on GitHub.
github.com
매력적인 풀이