백발백준하는 명사수

문제


백발백준은 무슨 과녁이던 백발백중하여 올림픽 금메달보다 따기 어렵다는 대한민국 양궁 국가대표 타이틀을 가지고 있다. 이런 백발백준이 현재 연마하는 스킬이 있는데… 바로 두 과녁을 한번에 맞추는 스킬이다. 이를 연습하기 위해 두 과녁이 겹치는 부분이 있어 한번에 맞추기가 가능한지 알아보고 싶어졌다. 여러분은 백발백준이 연습하는 과정을 도와주기 위해 원 모양으로 생긴 두 과녁이 겹치는 부분이 존재하는지 확인하는 프로그램을 작성해보자.

입력


첫번째 줄에는 첫번째 과녁의 중심 X1, Y1와 반지름 R1이 주어진다. 두번째 줄에는 두번째 과녁의 중심 X2, Y2와 반지름 R2가 주어진다. X1, X2, Y1, Y2는 모두 정수이며, R1, R2는 모두 자연수이다. -109 ≤ X1, X2, Y1, Y2 ≤ 109, 0 < R1, R2 ≤ 109

출력


두 과녁이 겹치면 YES, 아니면 NO를 출력한다. 단, 두 과녁이 한 점에서 만나는 경우는 겹치지 않는 것으로 생각한다.

예제 입력 1

0 0 1
1 1 2

예제 출력 1

YES

예제 입력 2

0 0 1
10 10 1

예제 출력 2

NO

BuffredReader 사용법

BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언
String s = br.readLine(); // String
int i = Integer.parseInt(br.readLine()); // Int

선언은 위에 있는 예제처럼 진행하면 된다.

입력은 readLine() 메서드를 활용하는데, 여기서 반드시 주의해야 할 점이 2가지 있습니다.
첫 번째는 readLine()이 리턴하는 값이 String으로 고정되어 있기 때문에 다른 타입으로 입력을 받으려면 형변환을 꼭 해주어야 한다는 점입니다.
두 번째는 예외 처리를 꼭 해주어야 한다는 점입니다. readLine()을 호출할 때마다 try & catch를 활용하여 예외 처리를 해주어도 되지만, 대개 throws IOException을 통해 작업합니다.

throw 이용 시

  1. 클래스를 import해주어야 합니다.

    import java.io.IOException;
    
  2. main 클래스 옆에 throws IOException를 작성합니다.

    public static void main(String[] args) throws IOException {}
    
StringTokenizer st = new StringTokenizer(s); // StringTokenizer인자값에 입력 문자열 넣음
int a = Integer.parseInt(st.nextToken()); // 첫번째 호출
int b = Integer.parseInt(st.nextToken()); // 두번째 호출

String array[] = s.split(" "); // 공백마다 데이터 끊어서 배열에 넣음

Read한 데이터는 Line 단위로만 나눠지기에 공백 단위로 데이터를 가공하려면 따로 작업을 해주어야 하는데, 위의 두 가지 방법이 대표적입니다.

  • 첫번째 방법으로는 StringTokenizer에 nextToken() 함수를 쓰면 readLine()을 통해 입력받은 값을 공백 단위로 구분하여 순서대로 호출할 수 있습니다.
  • 두번째 방법으로는 String.split() 함수를 활용하여 배열에 공백 단위로 끊어서 데이터를 넣고 사용하는 방식입니다.

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

public class Main {
    public static void main(String[] args) throws IOException {
        solution();
    }
    
    private static void solution() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int x = Integer.parseInt(st.nextToken());
        int y = Integer.parseInt(st.nextToken());
        int r = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        int x1 = Integer.parseInt(st.nextToken());
        int y1 = Integer.parseInt(st.nextToken());
        int r1 = Integer.parseInt(st.nextToken());
        if (1l*(x-x1)*(x-x1)+1l*(y-y1)*(y-y1) < 1l*(r+r1)*(r+r1)) {
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }
    }
}

이 코드에서 1l을 사용하는 이유는 자바에서의 정수 연산 오버플로우(overflow)를 방지하기 위한 것입니다.
여기서의 1l은 long 형으로의 형변환을 의미합니다.
이 코드에서는 각 항을 계산할 때 1l을 곱해주는 것으로, 해당 항이 long 형으로 처리되도록 강제하고 있습니다.

X, Y, R이 모두 최대 10^9의 큰 수일 수 있기 때문에, 제곱한 값이 int 범위를 넘어갈 수 있습니다.
따라서 long으로 연산을 수행해야 합니다. 최대 (r1+r2)^2의 값은 대략 (2 * 10^9)^2으로, 약 4 * 10^18입니다.
long은 대략 9 * 10^18까지 표현 가능하므로(정확히는 2^63-1), 이러한 큰 수도 문제없이 처리할 수 있습니다.

출처: 백준 문제 22938
문제풀이 참고: 나화사의 블로그
BufferedReader 참고: Ohsanrim 네이버 블로그

Leave a comment