알고리즘/구현 & 그리디 & 브루트포스

[백준]JAVA - 1002번: 터렛

K.두부 2022. 9. 28. 19:56
반응형

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

 

1002번: 터렛

각 테스트 케이스마다 류재명이 있을 수 있는 위치의 수를 출력한다. 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우에는 -1을 출력한다.

www.acmicpc.net

풀이

처음 문제를 봤을 때 이해가 잘 안갔다..

검색을 하고나서야 이해가 갔다. 하나씩 이해해보겠다.

 

문제에선 두 개의 터렛 x, y 좌표와 류재명과의 r1, r2가 제공된다.

그렇다면 x, y를 기준으로 r1, r2의 반지름을 가진 원을 그릴 수 있다.

 

두 개의 원이 그러졌다면 A 터렛의 원과 B 터렛의 원의 접점 개수를 구하면 된다.

두 개의 원을 그렸을 때 생기는 접점의 개수에 대한 경우의 수는 몇 개일까?

 

출처: 수학방(mathbang.net)

위 그림처럼 여러가지가 있겠지만 4가지로 나눌 수 있다.

1.두 개의 접점이 생기는 경우

2. 한 개의 접점이 생기는 경우

3. 겹치지 않는 경우

4. 두 개의 원이 겹치는 경우

 

 

1. 두 개의 접점이 생기는 경우

: 그림 (1)

else if (dist > Math.pow(r2-r1,2) && dist < Math.pow(r1+r2,2)) {
    arr[i] = 2;
}

2. 한 개의 접점이 생기는 경우

: 그림 (2), (3)

else if (Math.pow(r2-r1,2) == dist || Math.pow(r2+r1,2) == dist) {
    arr[i] = 1;
}

3. 겹치지 않는 경우

: 그림 (4), (5), (6)

else if (Math.pow(r1+r2,2) < dist || Math.pow(r2-r1,2) > dist || dist == 0) {
    arr[i] = 0;
}

4. 두 개의 원이 겹치는 경우

if (dist == 0 && r1 == r2) {
    arr[i] = -1;
}

여기서 나오는 dist 변수는 두 개의 원 중점의 거리이다.

대부분의 풀이를 보면 double 형 또는 float 형으로 변수를 선언해서 Math.sqrt 를 사용했다.

double dist = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));

하지만 이렇게 되면 정확한 값이 아니다. if-else 문을 통해서 간단한 연산을 해보면 쉽게 이해할 수 있다.

import java.io.*;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        double a = 0.1;
        double b = 0.2;
        double c = 0.3;
 
        if(a + b == c) System.out.print("참입니다.");
        else System.out.print("거짓입니다.");
    }
}

// 거짓입니다.

이러한 이유로 필자는 Math.sqrt 를 사용하지않고 Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2) 를 사용했다.

 

<최종코드>

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
		
        int T = Integer.parseInt(br.readLine());
        int[] arr = new int[T];
		
        for (int i=0; i<T; i++) {
            st = new StringTokenizer(br.readLine());
            int x1 = Integer.parseInt(st.nextToken());
            int y1 = Integer.parseInt(st.nextToken());
            int r1 = Integer.parseInt(st.nextToken());
            int x2 = Integer.parseInt(st.nextToken());
            int y2 = Integer.parseInt(st.nextToken());
            int r2 = Integer.parseInt(st.nextToken());
			
            // 두 개의 원 중점의 거리
            int dist = (int)(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
			
            // 두 개의 원이 겹치는 경우
            if (dist == 0 && r1 == r2) {
                arr[i] = -1;
            }
			
            // 두 개의 접점이 생기는 경우
            else if (dist > Math.pow(r2-r1,2) && dist < Math.pow(r1+r2,2)) {
                arr[i] = 2;
            }
			
            // 한 개의 접점이 생기는 경우
            else if (Math.pow(r2-r1,2) == dist || Math.pow(r2+r1,2) == dist) {
                arr[i] = 1;
            }
			
            // 겹치지 않는 경우
            else if (Math.pow(r1+r2,2) < dist || Math.pow(r2-r1,2) > dist || dist == 0) {
                arr[i] = 0;
            }
        }
		
        for (int num : arr) {
            System.out.println(num);
        }
    }
}
반응형