Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 유니온 파인드
- 에라토스테네스의 체
- 백준
- 수학
- 세그먼트 트리
- JUnit 5
- 플로이드-와샬
- 문자열
- 위상정렬
- 후니의 쉽게 쓴 시스코 네트워킹
- Kotlin
- Network
- 시뮬레이션
- BFS
- 알고리즘
- 프로그래머스
- 동적계획법
- swea
- 이분탐색
- 투 포인터
- 스택
- java
- 완전탐색
- dfs
- 그리디
- Effective Java
- CS
- 백트래킹
- mst
- 구현
Archives
반갑습니다!
[백준] 2234 성곽 본문
풀이
상당히 구현할게 많고 까다로운 문제였다. BFS를 사용해서 방을 분리하고, BFS를 한번 더 사용해서 각 방들끼리의 관계를 인접 리스트로 표현했다. 벽을 한개만 부셔도 2개의 방은 합쳐질 수 있으므로 서로 인접해 있는 방 2개의 합이 가장 큰 경우를 찾아주었다.
코드
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include <algorithm>
using namespace std;
int m, n;
bool can_left, can_up, can_right, can_down;
int map[51][51];
int area[51][51];
bool chk[51][51];
vector<int> v;
vector<set<int>> adj;
const int dx[] = { -1, 0, 1, 0 }, dy[] = { 0, -1, 0, 1 };
// 상하좌우로 이동할 수 있는지 확인해주는 함수
void can_move(int x, int y) {
can_left = false; can_up = false; can_right = false; can_down = false;
can_left = !(map[y][x] & 1);
can_up = !(map[y][x] & 2);
can_right = !(map[y][x] & 4);
can_down = !(map[y][x] & 8);
}
// 방을 나누기 위한 함수. 방의 크기를 계산하여 리턴
int bfs(int x, int y, int idx) {
int ret = 1;
queue<pair<int, int>> q;
area[y][x] = idx;
q.push({ x, y });
while (!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
// 상하좌우 이동할 수 있는지 확인
can_move(x, y);
// 왼쪽으로 이동가능한 경우
if (can_left && !area[y][x - 1]) {
area[y][x - 1] = idx;
q.push({ x - 1, y });
ret++;
}
// 위쪽으로 이동가능한 경우
if (can_up && !area[y - 1][x]) {
area[y - 1][x] = idx;
q.push({ x, y - 1 });
ret++;
}
// 오른쪽으로 이동가능한 경우
if (can_right && !area[y][x + 1]) {
area[y][x + 1] = idx;
q.push({ x + 1, y });
ret++;
}
// 아래쪽으로 이동가능한 경우
if (can_down && !area[y + 1][x]) {
area[y + 1][x] = idx;
q.push({ x, y + 1 });
ret++;
}
}
return ret;
}
// 인접리스트를 생성해주는 함수
void make_adj(int x, int y) {
queue<pair<int, int>> q;
q.push({ x, y });
chk[y][x] = true;
int idx = area[y][x];
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 > n || ny < 0 || ny > m) continue;
// 같은 방이면서 아직 방문하지 않은 경우
if (area[ny][nx] == idx && !chk[ny][nx]) {
q.push({ nx, ny });
chk[ny][nx] = true;
}
// 인접한 방을 발견한 경우 (방의 번호는 1번부터 시작하므로 방의 번호가 0번인 경우는 제외하였다)
else if(area[ny][nx] != 0 && area[ny][nx] != idx) adj[idx].insert(area[ny][nx]);
}
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
cin >> map[i][j];
int idx = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (area[i][j]) continue;
int tmp = bfs(j, i, idx++);
v.push_back(tmp);
}
}
adj = vector<set<int>>(v.size() + 1);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (chk[i][j]) continue;
make_adj(j, i);
}
}
int ans = 0;
for (int i = 1; i < adj.size(); i++) {
for (auto it = adj[i].begin(); it != adj[i].end(); it++) {
ans = max(ans, v[i-1] + v[(*it) - 1]);
}
}
cout << v.size() << '\n' << *max_element(v.begin(), v.end()) << '\n' << ans << '\n';
return 0;
}
'알고리즘 문제 풀이' 카테고리의 다른 글
[프로그래머스] 자동완성 (0) | 2020.04.23 |
---|---|
[백준] 5052 전화번호 목록 (0) | 2020.04.23 |
[백준] 1600 말이 되고픈 원숭이 (0) | 2020.04.22 |
[백준] 1726 로봇 (0) | 2020.04.22 |
[백준] 1063 킹 (0) | 2020.04.22 |