티스토리 뷰

Algorithm

[백준1004번/자바] 어린 왕자

도도고영 2024. 7. 14. 19:29

문제

어린 왕자는 소혹성 B-664에서 자신이 사랑하는 한 송이 장미를 위해 살아간다. 어느 날 장미가 위험에 빠지게 된 것을 알게 된 어린 왕자는, 장미를 구하기 위해 은하수를 따라 긴 여행을 하기 시작했다. 하지만 어린 왕자의 우주선은 그렇게 좋지 않아서 행성계 간의 이동을 최대한 피해서 여행해야 한다. 아래의 그림은 어린 왕자가 펼쳐본 은하수 지도의 일부이다.

빨간 실선은 어린 왕자가 출발점에서 도착점까지 도달하는데 있어서 필요한 행성계 진입/이탈 횟수를 최소화하는 경로이며, 원은 행성계의 경계를 의미한다. 이러한 경로는 여러 개 존재할 수 있지만 적어도 3번의 행성계 진입/이탈이 필요하다는 것을 알 수 있다.

위와 같은 은하수 지도, 출발점, 도착점이 주어졌을 때 어린 왕자에게 필요한 최소의 행성계 진입/이탈 횟수를 구하는 프로그램을 작성해 보자. 행성계의 경계가 맞닿거나 서로 교차하는 경우는 없다. 또한, 출발점이나 도착점이 행성계 경계에 걸쳐진 경우 역시 입력으로 주어지지 않는다.

입력

입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 첫째 줄에 출발점 (x1, y1)과 도착점 (x2, y2)이 주어진다. 두 번째 줄에는 행성계의 개수 n이 주어지며, 세 번째 줄부터 n줄에 걸쳐 행성계의 중점과 반지름 (cx, cy, r)이 주어진다.

 

출력

각 테스트 케이스에 대해 어린 왕자가 거쳐야 할 최소의 행성계 진입/이탈 횟수를 출력한다.

제한

  • -1000 ≤ x1, y1, x2, y2, cx, cy ≤ 1000
  • 1 ≤ r ≤ 1000
  • 1 ≤ n ≤ 50
  • 좌표와 반지름은 모두 정수

 

처음에는 '엥??? 못하겠는데' 했지만

다시 보니 이 문제에서 필요한 동그라미는 출발점과 도착점을 포함하고 있는 동그라미들이다!

할 수 있을거 같다! 아마도!

 

2
-5 1 12 1	// 출발지, 도착지
7		// 원 개수
1 1 8     	// 원
-3 -1 1   	// ...
2 2 2
5 5 1
-4 5 1
12 1 1
12 1 2		
-5 1 5 1	// 출발지, 도착지
1		// ...
0 0 2

 

위 테스트 케이스를 기반으로 출발지가 (-5,1)인 좌표 중심점이 (1,1) 그리고 반지름이 8인 원의 관계를 살펴보자.

(1) 두점의 거리를 구한다. (피타고라스의 정리...? 맞나?) / 제곱근을 구하면 부가적인 연산이 필요하기에 나는 제곱이 된 상태의 값을 사용하겠다.

(2) 두점의 거리가 반지름(제곱)의 길이보다 짧으면 원의 내부에 존재한다!!!

 

그럼 이제 구현을 해보자. 아래와 같이 코드를 작성했다. 기깔나게 잘풀었다 생각했는데...

틀렸습니다가 뜬다... 오케이... 한번에 될리가 없지. 👌

 

우선 뭐가 문제인지 모르겠는 코드 첨부한다. 제시된 예시 테스트 케이스는 모두 넘어간다.

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

public class BJ1004 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int t = Integer.parseInt(br.readLine());    // 테스트 케이스 개수
        for (int i = 0; i < t; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            Point start = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
            Point end = new Point(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
            
            int n = Integer.parseInt(br.readLine());    // 행성계의 개수
            int cnt = 0;    // 거쳐야 되는 원의 개수 카운트
            for (int j = 0; j < n; j++) {
                st = new StringTokenizer(br.readLine());
                Circle circle = new Circle(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
                cnt = start.isInside(circle)? cnt + 1 : cnt;
                cnt = end.isInside(circle)? cnt + 1 : cnt;
            }
            System.out.println(cnt);
        }

    }
}

class Point {
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    boolean isInside(Circle circle) {
        int a = Math.abs(this.x - circle.x);
        int b = Math.abs(this.y - circle.y);
        int c = circle.radius;
        return (a * a + b * b) < (c * c);
    }
}

class Circle extends Point {
    int radius;

    public Circle(int x, int y, int radius) {
        super(x, y);
        this.radius = radius;
    }
}

 

뭐가 잘못된걸까 고민하다가 놓친 지점을 찾았다.

출발점과 도착점이 모두 원 안에 있을 경우는 답이 0이 나와한다. 

다시 해보자...!

 

중간 코드를 아래와 같이 수정, 추가했다. 

boolean startIsInside = start.isInside(circle);
boolean endIsInside = end.isInside(circle);

if(startIsInside && endIsInside) { // 명시적
    continue;
} else {
    cnt = startIsInside? cnt + 1 : cnt;
    cnt = endIsInside? cnt + 1 : cnt;
}

 

 

며칠에 거쳐 정답!

이번 문제는 1시간 33분 걸렸다. 

오래 걸리긴 했지만... 뿌듯하다 :)

 

'Algorithm' 카테고리의 다른 글

[백준9375번/자바] 패션왕 신해빈  (0) 2024.07.05
[백준13305번/자바] 주유소  (0) 2024.07.01
[백준1021/자바] 회전하는 큐  (1) 2024.03.29
[백준1094/자바]  (0) 2024.03.24
[백준2193번/자바] 이친수  (1) 2024.03.23
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함