-
[백준 2573] 빙산백준/BFS 2023. 7. 7. 01:34
지금까지 푼 DFS/BFS 문제 중 제일 난이도 있는 문제였음
풀면서 BFS뿐만 아니라 그 외 것들을 구현하는데 생각을 더 해야했음
1. 우선 가장 중요한건 BFS돌면서 빙하를 녹이면 안된다는거임
왜냐하면 하면서 녹이면 그 다음꺼가 바다랑 맞닿는 면의 개수에 영향을 끼치기 때문
그래서 녹일 양을 따로 저장해야함
2. 그 다음으로 중요한게 2분할 됐냐 확인하는거임
이건 모든 원소 다 돌면서 visited 됐는지 확인하고 BFS돌리고 그러면서 cnt++ 해서 판단가능함
BFS 한 턴으로 다 돌면 정상이고
BFS가 두 턴 이상 나오면 break
BFS가 0이면 다 녹았다는 뜻이므로 종료
BFS가 0번이면 그건 다 녹을때까지 cnt가 두 번 이상 안나왔다는 뜻이므로 바로 종료해주면 된다
for (int i = 0; i < iceberg.size(); i++) { int y = iceberg[i].first; int x = iceberg[i].second; // 빙하가 있고 아직 탐색X if (ocean[y][x] && !visited[y][x]) { BFS(y, x); cnt++; } } // 다 녹았으면 if (cnt == 0) { cout << "0"; break; } // 만약 이분할 되었으면 종료 if (cnt > 1) { cout << year; break; }

3. 빙하 위치는 희소행렬로 저장해놓자
4. 사분면은 dx dy로 미리 저장해놓음. 거의 dfs bfs 할때 필수
쨋든... 뭐 재밌는 문제인데 시간이 많이 걸림
참고로 vs에서는 memset이 바로 되는데 백준은 cstring이나 memory.h 안해주면 컴파일 에러뜸...
개억울하게 컴파일에러 하나 적립함...
엔샵하다 다시 코테 감 잡는다고 다시 푼 풀이
첫번째보다 훨씬 잘 푼듯
#include <iostream> #include <vector> #include <queue> #include <bitset> #define SIZE 301 using namespace std; int dx[4] = { -1,0,0,1 }; int dy[4] = { 0,-1,1,0 }; int N, M; int map[SIZE][SIZE]; int ans; vector<pair<int, int>> iceberg; // 한번의 BFS로 확인한 녹아야하는 빙하 좌표와 녹는 양 vector<pair<pair<int, int>, int>> melting; void bfs() { queue<pair<int, int>> q; bitset<SIZE> visited[SIZE]; q.push(make_pair(iceberg[0].first, iceberg[0].second)); visited[iceberg[0].first][iceberg[0].second] = 1; while (!q.empty()) { int y = q.front().first; int x = q.front().second; q.pop(); int meltingcnt = 0; for (int i = 0; i < 4; i++) { int newy = y + dy[i]; int newx = x + dx[i]; if (map[newy][newx] == 0) meltingcnt++; // 빙하고 아직 방문 안했으면 if (map[newy][newx] && !visited[newy][newx]) { visited[newy][newx] = 1; q.push(make_pair(newy, newx)); } } melting.push_back(make_pair(make_pair(y, x), meltingcnt)); } } void meltice() { // 녹여주기 for (int i = 0; i < melting.size(); i++) { int y = melting[i].first.first; int x = melting[i].first.second; int cnt = melting[i].second; map[y][x] -= cnt; if (map[y][x] <= 0) map[y][x] = 0; else { iceberg.push_back(make_pair(y, x)); } } melting.clear(); } void solve() { int ans = 0; while(1) { bfs(); // 빙하가 두 개로 나눠졌으면 종료 if (melting.size() != iceberg.size()) break; iceberg.clear(); meltice(); if (iceberg.size() == 0) { cout << 0; return; } ans++; } cout << ans; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> N >> M; for (int y = 0; y < N; y++) { for (int x = 0; x < M; x++) { cin >> map[y][x]; if (map[y][x] > 0) { iceberg.push_back(make_pair(y, x)); } } } if (iceberg.size() == 0) { cout << 0; return 0; } solve(); return 0; }실제로 시간이랑 메모리도 반이상 줄었다
이분할됐는지 확인하는것을 따른 배열로 하지 않고
그냥 melting 배열을 사용해서 확인함
iceberg랑 melting vector 크기가 같으면 아직 이분할 안됐다는거 확인가능
#include <iostream> #include <vector> #include <queue> #include <cstring> #define SIZE 300 using namespace std; int N, M; int ocean[SIZE][SIZE]; int melt[SIZE][SIZE]; int dx[4] = { 0,1,0,-1 }; int dy[4] = { -1,0,1,0 }; bool visited[SIZE][SIZE]; // 빙하 희소행렬 vector<pair<int, int>> iceberg; // 빙하 BFS void BFS(int y,int x) { queue<pair<int,int>> q; q.push(make_pair(y,x)); while (!q.empty()) { int posy = q.front().first; int posx = q.front().second; q.pop(); // 해당 빙하를 방문하지 않았으면 if (!visited[posy][posx]) { // 방문처리 해주고 visited[posy][posx] = true; int melting = 0; for (int i = 0; i < 4; i++) { int newy = posy + dy[i]; int newx = posx + dx[i]; // 범위 내 if (newy >= 0 && newy < N && newx >= 0 && newx < M) { // 아직 방문 안한 빙하 if (ocean[newy][newx] && !visited[newy][newx]) q.push(make_pair(newy, newx)); // 바다 if(!ocean[newy][newx]) melting++; } } // 추후에 녹일 빙산 저장 melt[posy][posx] = melting; } } return; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> N >> M; for (int i = 0; i < N; i++) { for (int k = 0; k < M; k++) { cin >> ocean[i][k]; if (ocean[i][k]) { iceberg.push_back(make_pair(i, k)); } } } int year = 0; int cnt; while(1){ // 빙하 BFS cnt = 0; memset(visited, false, sizeof(visited)); for (int i = 0; i < iceberg.size(); i++) { int y = iceberg[i].first; int x = iceberg[i].second; // 빙하가 있고 아직 탐색X if (ocean[y][x] && !visited[y][x]) { BFS(y,x); cnt++; } } // 빙하 녹여주기 for (int i = 0; i < iceberg.size(); i++) { int y = iceberg[i].first; int x = iceberg[i].second; if (ocean[y][x]) ocean[y][x] -= melt[y][x]; if (ocean[y][x] < 0) ocean[y][x] = 0; } // 다 녹았으면 if (cnt == 0) { cout << "0"; break; } // 만약 이분할 되었으면 종료 if (cnt > 1) { cout << year; break; } // 1이면 계속 실행 year++; } return 0; }'백준 > BFS' 카테고리의 다른 글
[백준 7576] 토마토 (1) 2024.01.09 [백준 24444] 알고리즘 수업 - 너비 우선 탐색 1 (0) 2023.09.15 [백준 13565] 침투 (0) 2023.09.12 [백준 11725] 트리의 부모 찾기 (0) 2023.06.30 [백준 2178] 미로 탐색 (0) 2023.05.12