문제
해결 방안 고민
이석원(명령자)
== 터렛 근무자 ==
조규현(x1, y1) => r1, 조규현이 계산한 류재명과의 거리
백승환(x2, y2) => r2, 백승환이 계산한 류재명과의 거리
류재명(상대편 마린)
== 입력 ==
첫째 줄: 테스트 케이스
둘째 줄:
한 줄에 공백으로 구분 된 여섯 정수 x1, y1, r1, x2, y2, r2가 주어짐
== 출력 ==
류재명이 있을 수 있는 좌표의 수를 출력
만약 류재명이 있을 수 있는 위치의 개수가 무한대인 경우 -1 출력
== 풀이 ==
x1, y1, r1
x2, y2, r2
r1 = Math.sqrt(Math.pow((x1 - x3), 2) + Math.pow((y1 - x3), 2))
r2 = Math.sqrt(Math.pow((x2 - x3), 2) + Math.pow((y2 - x3), 2))
-- 두 원의 접점에 대한 경우의 수를 고려 ---
1. 두 원의 중심이 같고, 반지름도 같을 때 (접점의 개수가 무한할 때)
2. 접점이 없을 때
1. 두 점 사이의 거리가 각 원의 반지름의 합보다 클 때
2. 한 원 안에 다른 원이 있으면서 접점이 없을 때
3. 접점이 한 개일 때
1. 내접할 때
2. 외접할 때
위 조건들에 만족하지 않을 경우 접점은 두 개!!!
Java
복사
•
이 문제를 처음 접했을 때 도대체 무슨 소리인가 싶어서 한참을 고민했다.
•
처음에는 두 점 사이의 거리를 통해 문제풀이를 할 수 있다는 생각을 했다.
•
하지만 아무리 식을 세우고 여러 방법으로 고민을 해도 좀처럼 실마리가 풀리지 않았다.
해결 방법
•
이 문제, 사실 r1, r2에서 어느 정도 힌트를 알았어야 했다. 여기서 r1, r2를 반지름이라고 놓고 생각했다면 x1, y1, x2, y2를 원들의 중점으로 인식하고 접근했을 것이다. 하지만 그러한 부분에 대해 전혀 생각하지 못햇다.
•
위치의 수를 찾아야 하기 때문에 각 터렛의 위치를 중심으로 C와의 거리를 반지름으로 하는 원을 그린다.
•
이 문제는 몇 가지 경우의 수를 고려해야 한다.
◦
두 원의 중심이 같고, 반지름도 같을 때(𝑥₁ = 𝑥₂, 𝑦₁ = 𝑦₂, 𝑟₁ = 𝑟₂)
◦
접점이 없을 때
▪
두 점 사이의 거리가 각 원의 반지름의 합보다 클 때
▪
(𝑥₂ - 𝑥₁)² + (𝑦₂ - 𝑦₁)² > (𝑟₁ + 𝑟₂)²
▪
한 원 안에 다른 원이 있으면서 접점이 없을 때
▪
(𝑥₂ - 𝑥₁)² + (𝑦₂ - 𝑦₁)² < (𝑟₂ - 𝑟₁)²
◦
접점이 한 개일 때
▪
내접할 때 - 두 반지름의 차가 두 좌표 간의 차랑 같으면 내접이다.
▪
(𝑥₂ - 𝑥₁)² + (𝑦₂ - 𝑦₁)² = (𝑟₂ - 𝑟₁)²
▪
외접할 때 - 두 좌표 간의 거리가 두 반지름의 합과 같으면 외접이다.
▪
(𝑥₂ - 𝑥₁)² + (𝑦₂ - 𝑦₁)² = (𝑟₂ + 𝑟₁)²
•
만약 위 조건에 만족하지 않으면 당연히 접점은 두 개다.
코드
package algo250225;
import java.io.*;
import java.util.*;
// 터렛 - 실버 3
public class Back1002 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; i++) {
StringTokenizer 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());
sb.append(answer(x1, y1, r1, x2, y2, r2)).append('\n');
}
System.out.println(sb);
}
// 접점 개수 구하기
public static int answer(int x1, int y1, int r1, int x2, int y2, int r2) {
int distance = (int)(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); // 중점간 거리
// 중점이 같으면서 반지름도 같은 경우(case 1)
if (x1 == x2 && y1 == y2 && r1 == r2) {
return -1;
} else if (distance > Math.pow(r1 + r2, 2)) { // 두 원의 반지름의 합보다 중점간 거리가 더 긴 경우(case 2-1)
return 0;
} else if (distance < Math.pow(r2 - r1, 2)) { // 원 안에 원이 있느나 내접하지 않을 때(case 2-2)
return 0;
} else if (distance == Math.pow(r2 - r1, 2)) { // 내접하는 경우(case 3-1)
return 1;
} else if (distance == Math.pow(r1 + r2, 2)) { // 외접하는 경우(case 3-2)
return 1;
} else {
return 2;
}
}
}
Java
복사
정리
이 문제는 다양한 케이스를 고려하여 풀어야 하는 문제이다. 특히나 수학적인 접근을 하지 못하면 풀기 쉽지 않은 문제인데 이런 상황을 접할 때마다 수학적 사고력과 알고리즘은 불가분의 관계라는 느낌을 지우지 않을 수가 없다. 그렇다. 알고리즘은 수학과 매우 직접적으로 연결되어 있다. 그렇기 때문에 수학을 무시하고 단순히 논리적으로만 뭔가를 접근한다면 프로그래밍 실력을 끌어올리는 것은 지극히 한계가 있을 수밖에 없다. 고로 수학은 기피해야 할 대상이 아닌 친해져야 할 대상인 것이다.