지우너

[BOJ] 3108 java 본문

Problem Solving

[BOJ] 3108 java

지옹 2025. 1. 3. 17:37

문제

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

 

그룹으로 묶어주는 문제라서 union-find를 사용.

bfs나 dfs로 풀려고 했는데, 블로그를 찾아보니 union-find를 사용하는 것을 보고 놀랐다.

사각형이 교차하는 조건이 조금 까다로워 보여서, 그냥 생각했을 때, 상하로 떨어지거나 좌우로 떨어지면 겹치지 않는다고 생각했다.

계속 예제 출력과 다른 답이 나와서 다시 블로그를 봤더니, 한 사각형이 다른 사각형 안에 있는 경우도 고려해야 했음.

 

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

    public static class Square{
        int x1, y1, x2, y2;

        public Square(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }
    }

    public static int n;
    public static int[] uf;
    public static Square[] squares;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        // 첫째 줄에 직사각형의 개수 N이 주어진다. (1 ≤ N ≤ 1000)
        int n = Integer.parseInt(br.readLine());

        // union-find 배열 초기화
        uf = new int[n+1];
        for (int i = 0; i <= n; i++) {
            uf[i] = i;
        }

        // 다음 N개의 줄에는 직사각형의 좌표 x1, y1, x2, y2가 주어진다. (−500 ≤ x1 < x2 ≤ 500), (−500 ≤ y1 < y2 ≤ 500)
        // (x1, y1)는 직사각형의 한 꼭짓점 좌표이고, (x2, y2)는 그 점의 대각선 방향의 반대 꼭짓점의 좌표이다.
        squares = new Square[n+1];
        // 연필을 내리면 움직일 때 화면에 선을 그리고, 올리면 선을 그리지 않고 그냥 지나가기만 한다.
        // 제일 처음에 거북이는 (0,0)에 있고, 거북이가 보고 있는 방향은 y축이 증가하는 방향이다. 또한 연필은 내리고 있다.
        squares[0]= new Square(0, 0, 0, 0);
        for (int i = 1; i <= n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int x1 = Integer.parseInt(st.nextToken());
            int y1 = Integer.parseInt(st.nextToken());
            int x2 = Integer.parseInt(st.nextToken());
            int y2 = Integer.parseInt(st.nextToken());

            squares[i] = new Square(x1, y1, x2, y2);
        }
        br.close();

        // 연결되어 있다면 union으로 같은 그룹 체크
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j <= n; j++) {
                if(isConnected(squares[i], squares[j])){
                    union(i, j);
                }
            }
        }

        // N개의 직사각형을 그리는 필요한 PU명령의 최솟값을 출력
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i <= n; i++) {
            set.add(find(i));
        }
        System.out.println(set.size()-1);
    }

    // 두 사각형이 만나는 점이 있는지 체크하기
    public static boolean isConnected(Square a, Square b) {
        // 상하로 떨어진 경우
        if (a.x2 < b.x1 || b.x2 < a.x1) return false;
        // 좌우로 떨어진 경우
        if (a.y2 < b.y1 || b.y2 < a.y1) return false;

        // a 안에 b가 있음
        if(a.x1<b.x1 && a.y1<b.y1 && a.x2> b.x2 && a.y2 > b.y2) return false;
        // b 안에 a가 있음
        if(b.x1<a.x1 && b.y1<a.y1 && b.x2 > a.x2 && b.y2 > a.y2) return false;

        return true;
    }

    public static int find(int x){
        if(uf[x]==x) return x;
        return uf[x] = find(uf[x]);
    }

    public static void union(int x, int y){
        int rootX = find(x);
        int rootY = find(y);
        if(rootX!=rootY){
            uf[rootX]=rootY;
        }
    }

}

 

'Problem Solving' 카테고리의 다른 글

[BOJ] 1987 java  (0) 2025.01.05
[BOJ] 1759 java  (0) 2025.01.04
[BOJ] 1963 java  (0) 2025.01.03
[BOJ] 1476 JAVA  (0) 2024.12.30
[BOJ] 4963 JAVA  (0) 2024.12.17