문제
조규현과 백승환은 터렛에 근무하는 직원이다. 하지만 워낙 존재감이 없어서 인구수는 차지하지 않는다. 다음은 조규현과 백승환의 사진이다.
이석원은 조규현과 백승환에게 상대편 마린(류재명)의 위치를 계산하라는 명령을 내렸다. 조규현과 백승환은 각각 자신의 터렛 위치에서 현재 적까지의 거리를 계산했다.
조규현의 좌표 (x1, y1)와 백승환의 좌표 (x2, y2)가 주어지고, 조규현이 계산한 류재명과의 거리 r1과 백승환이 계산한 류재명과의 거리 r2가 주어졌을 때, 류재명이 있을 수 있는 좌표의 수를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 이루어져 있다.
한 줄에 x1, y1, r1, x2, y2, r2가 주어진다. x1, y1, x2, y2는 -10,000보다 크거나 같고, 10,000보다 작거나 같은 정수이고, r1, r2는 10,000보다 작거나 같은 자연수이다.
출력
각 테스트 케이스마다 류재명이 있을 수 있는 위치의 수를 출력한다. 만약 류재명이 있을 수 있는 위치의 개수가 무한대일 경우에는 -1을 출력한다.
입력 예시1 6 0 0 13 40 0 37 0 0 3 0 7 4 -1 -1 1 10 10 1 1 1 1 1 1 1 0 0 2 1 0 1 1 1 1 1 1 5 |
출력 예시1 2 1 0 -1 1 0 |
입력 예시2 8 0 0 1 0 0 1 0 0 1 0 2 1 0 0 2 0 1 1 0 0 1 2 2 1 0 0 5 0 1 1 0 0 1 0 1 1 1 2 5 0 1 2 0 0 3 2 0 2 |
출력 예시2 -1 1 1 0 0 2 0 2 |
입력 예시3 1 0 0 1 1 1 9999 |
출력 예시3 0 |
입력 예시4 2 0 0 1 0 0 1 0 0 10 0 1 1 |
출력 예시4 -1 0 |
문제풀이
이 문제는 두 원의 접점의 갯수를 구하는 문제이다.
두 원의 접점의 갯수를 구하려면 먼저 두 원이 만나는 경우부터 살펴보아야 한다.
두 원이 만나는 경우는 위 그림처럼 6가지의 경우가 있다.
위의 1~3번은 모두 외접하는 경우이고 4~6번은 모두 내접하는 경우이다.
그렇다면 먼저 외접과 내접하는 경우를 구분해줘야 하는데 이때 주어진 두 반지름의 크기 순서를 정해야하고, 주어진 두 점 사이의 거리가 필요하다. 왜냐하면 [두 점 사이의 거리]가 큰 반지름보다 크다면 외접, 작다면 내접으로 판단할 수 있기 때문이다.
먼저 위 그림처럼 변수들을 선언하고 값들을 입력받는다.
그 후 큰 반지름과 작은 반지름, 그리고 두 점 사이의 거리를 구해준다. 두 점 사이의 거리는 (x2-x1)² + (y2-y1)²의 제곱근으로 구할 수 있다.
그리고 만약 두 점 사이의 거리가 0이고 반지름이 똑같다면 위 원 그림에서 4번과 같기 때문에 result에 -1을 저장하고 반복문으로 간다.
그리고 distance와 big(큰 반지름)을 비교하여 distance가 작다면 내접한 것이므로 big-small의 값이 distance보다 큰지 작은지 같은지 비교하여 각각의 결과를 result배열에 저장해준다.
distance가 big(큰 반지름)보다 크다면 외접한 것이므로 big+small의 값을 distance와 비교하여 각각의 결과를 result에 저장해준다.
위 두 소스코드에서 주석부분의 숫자는 위 원 그림들의 숫자에 해당하는 두 원의 상태를 가리킨다.
그 후 결괏값을 출력해준다.
소스코드
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
|
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int n = Integer.parseInt(br.readLine()); // 입력받을 갯수
int big = 0; // 큰 반지름
int small = 0; // 작은 반지름
double distance = 0; // 두 점 사이의 거리
int[][] coord = new int[n][6]; // 입력받은 값들의 배열
int[] result = new int[n]; // 출력할 값을 저장하는 배열
for(int i = 0 ; i < n ; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0 ; j < 6 ; j++) coord[i][j] = Integer.parseInt(st.nextToken());
}
for(int i = 0 ; i < n ; i++) {
big = coord[i][2] >= coord[i][5] ? coord[i][2] : coord[i][5]; // 큰 반지름
small = coord[i][2] >= coord[i][5] ? coord[i][5] : coord[i][2]; // 작은 반지름
distance = Math.sqrt(Math.pow(coord[i][3]-coord[i][0],2)+Math.pow(coord[i][4]-coord[i][1],2)); // 두 점 사이의 거리
// 두 점 사이의 거리가 0이고 반지름이 서로 같다면 두 원은 동일
// 4
if(distance==0 && big==small) {
result[i] = -1;
continue;
}
// 두 점 사이의 거리가 큰 반지름보다 작다면 내접
if (distance < big)
{
if (distance > big - small) result[i] = 2; // 1
else if (distance == big - small) result[i] = 1; // 5
else if (distance < big - small) result[i] = 0; // 6
}
// 두 점 사이의 거리가 큰 반지름보다 크거나 같다면 외접
else
{
if (distance < big + small) result[i] = 2; // 1
else if (distance == big + small) result[i] = 1; // 2
else if (distance > big + small) result[i] = 0; // 3
}
}
for(int i = 0 ; i < n ; i++) {
bw.write(result[i]+"\n");
bw.flush();
}
bw.close();
}
}
|
cs |
느낀점
이 문제는 쉬운 줄 알고 TDD를 하지 않았는데 알고보니 복잡한 문제여서 좀 진심으로 풀어볼 걸 하는 아쉬움이 남는다.
특히나 이번 문제는 입력값이 많아서 출력값들도 다양하다. 그래서 다양한 입력값을 대입해서 제대로 작동하는지 확인해야 하는데 백준에서는 그걸 안알려주니 틀리고 틀리고 하다가 결국 열심히 질문 검색에서 반례를 하나하나 입력해서 정답을 찾았다.
담부턴 junit 테스트를 습관화 해야겠다.
'백준 온라인 저지 문제풀이 > JAVA' 카테고리의 다른 글
[baekjoon 2447번] 재귀 - 별 찍기 - 10 (0) | 2020.12.30 |
---|---|
[baekjoon 10872번, 10870번] 재귀 - 팩토리얼, 피보나치 (0) | 2020.12.29 |
[baekjoon 3053번] 수학 2 - 택시 기하학 (0) | 2020.12.18 |
[baekjoon 1085번] 수학 2 - 직사각형에서 탈출 (0) | 2020.12.17 |
[baekjoon 9020번] 수학2 - 골드바흐의 추측 (0) | 2020.12.17 |