본문 바로가기

문제풀이/백준

백준 4001 미노타우르스 미궁

https://www.acmicpc.net/problem/4001

 

거의 반 년 동안 큐에 들어있던 문제인데 도저히 못 풀겠더라

그동안 못 푼 문제 풀이 까기에 대한 강박적인 거부감이 있었는데, 최근에 이런저런 대화와 생각을 거치며 거부감이 줄어서 풀이를 찾아봤다. 

https://leo630.tistory.com/138

 

BOJ 4001 - 미노타우르스 미궁

꽤 오래 전부터 보던 문제인데, 도저히 모르겠어 태그를 까고 생각해보았다. 문제 요약 길 또는 장애물로 이루어진 격자가 주어진다. 이 때 장애물이나 시작, 끝 지점을 포함하지 않으면서 시작

leo630.tistory.com

 

최소 정사각형을 찾는다는 목표와 O(wh log w) 정도가 돌 제한에서 이분 탐색 냄새가 진하게 났는데, 처음 들어간 잘못된 방향에서 헤어나오질 못 했다. 격자에서 연결된다 <-> 양끝 벽이 안 이어진다는 여러 번(https://www.acmicpc.net/problem/24515, https://www.acmicpc.net/problem/34221) 썼던 관찰인데 못 떠올린 게 많이 아쉽다. 생각해보니까 24515도 풀이 까고 풀었던 것 같다.. 이 관찰을 못 한 탓에 임의의 정사각형을 잡았을 때 양 끝 점이 끊기는지 판별이 상수 시간에 절대 안 된다고 생각해서 크기 같은 정사각형을 한번에 어떻게 잘 처리해야된다고 생각했는데, 정사각형의 좌표가 고정되지 않으면 크기에 대한 단조성이 없어져서 어떻게 할지 도저히 감이 안 왔다. 먼가 플로우일지도 모른다는 생각도 들고.. 한 번 꼬이기 시작하니까 답이 없더라

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <bits/stdc++.h>
using namespace std;
 
int chk[1515][1515], lchk[1515][1515], rchk[1515][1515], w, h;
char mp[1515][1515];
const int dx[] = {-1-1-100111}, dy[] = {-101-11-101};
 
void dfs(int x, int y, int (*c)[1515]){
    c[y][x] = 1;
    for (int i = 0; i < 8; i++) {
        int nx = x + dx[i], ny = y + dy[i];
        if (0 <= nx and nx <= w+1 and 0 <= ny and ny <= h+1 and mp[ny][nx] == '#' and !c[ny][nx])   
            dfs(nx, ny, c);
    }
}
 
int sum(int xs, int ys, int xe, int ye, int (*A)[1515]) {
    if (!xs and !ys) return A[ye][xe];
    if (!xs) return A[ye][xe] - A[ys-1][xe];
    if (!ys) return A[ye][xe] - A[ye][xs-1];
    return A[ye][xe] - A[ye][xs-1- A[ys-1][xe] + A[ys-1][xs-1];
}
 
int main() {
    cin.tie(nullptr)->sync_with_stdio(0);
 
    cin >> w >> h;
    for (int i = 1; i <= h; i++)
        for (int j = 1; j <= w; j++){
            cin >> mp[i][j];
            chk[i][j] = mp[i][j] == '#';
        }
    for (int i = 2; i <= h+1; i++) mp[i][0= '#';
    for (int i = 0; i <= h-1; i++) mp[i][w+1= '#';
    for (int i = 2; i <= w+1; i++) mp[0][i] = '#';
    for (int i = 0; i <= w-1; i++) mp[h+1][i] = '#';
    dfs(20, rchk);
    dfs(02, lchk);
    
    for (int i = 1; i <= h+1; i++) {
        chk[i][0+= chk[i-1][0];
        lchk[i][0+= lchk[i-1][0];
        rchk[i][0+= rchk[i-1][0];
    }
    for (int i = 1; i <= w+1; i++){
        chk[0][i] += chk[0][i-1];
        lchk[0][i] += lchk[0][i-1];
        rchk[0][i] += rchk[0][i-1];
    }
    for (int i = 1; i <= h+1; i++)
        for (int j = 1; j <= w+1; j++){
            chk[i][j] += chk[i-1][j] + chk[i][j-1- chk[i-1][j-1];
            lchk[i][j] += lchk[i-1][j] + lchk[i][j-1- lchk[i-1][j-1];
            rchk[i][j] += rchk[i-1][j] + rchk[i][j-1- rchk[i-1][j-1];
        }
    int ans = 1e9, x = -1, y = -1;
    for (int i = 1; i <= h; i++){
        for (int j = 1; j <= w; j++){
            if (mp[i][j] == '#' or (i == 1 and j == 1) or (i == h and j == w)) continue;
            int yes = 1, no = max(w, h);
            while (yes+1 < no) {
                int m = yes+no >> 1;
                if (j+m-1 <= w and i+m-1 <= h and (j+m-1 < w or i+m-1 < h) and !sum(j, i, j+m-1, i+m-1, chk))
                    yes = m;
                else
                    no = m; 
            }
            if (!sum(j-1, i-1, j+yes, i+yes, lchk) or !sum(j-1, i-1, j+yes, i+yes, rchk)) continue;
            no = 0;
            while (no+1 < yes) {
                int m = no+yes >> 1;
                if (sum(j-1, i-1, j+m, i+m, lchk) and sum(j-1, i-1, j+m, i+m, rchk))
                    yes = m;
                else
                    no = m;
            }
            if (yes < ans) ans = yes, x = j, y = i;
        }
    }
    if (x == -1cout << "Impossible";
    else cout << ans << ' ' << x << ' ' << y;
}
cs

 

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

백준 8217 유성  (0) 2025.12.21
백준 11001 김치  (2) 2025.12.18
백준 3408 Non-boring sequences  (0) 2025.12.02
백준 3654 L퍼즐  (0) 2025.11.30
백준 19651 수열과 쿼리 39  (0) 2025.11.09