시리즈: 알고리즘 (32개 글)
- 자바로 알고리즘 풀기
- [Java] 백준 10431 - 줄 세우기
- [Java & Node.js] 백준 9935 - 문자열 폭발
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 4485 - 녹색 옷 입은 애가 젤다지?
- [Node.js] 백준 1283 - 단축키 지정
- [Java & Node.js] 백준 14469 - 소가 길을 건너간 이유 3
- [Java] 백준 8979 - 올림픽
- [Node.js] 백준 22866 - 탑 보기
- [Java] 백준 7568 - 덩치
- [Java] 백준 1244 - 스위치 켜고 끄기
- [Node.js] 백준 19941 - 햄버거 분배
- [Node.js] 백준 1254 - 팰린드롬 만들기
- [Java] 백준 2589 - 보물섬
- [Java] 백준 2309 - 일곱 난쟁이
- [Java] 백준 1789 - 수들의 합
- [Java] 백준 1987 - 알파벳
- [Node.js] [Rust] 백준 24460 - 특별상이라도 받고 싶어
- [Node.js] 백준 7576 - 탑 보기
- [Rust] 백준 1047 - 울타리 (N^4 브루트포스 + 그리디)
- [Node.js] 백준 9657 - 돌게임3
- [Rust] 백준 4963 - 섬의 개수
- [Node.js] 프로그래머스 - 모의고사 / 실패율
- [Rust] 백준 2667 - 단지번호붙이기
- [Node.js] 프로그래머스 - 방문 길이
- [Node.js] 프로그래머스 - 괄호 회전하기
- [Rust] 백준 1002 - 터렛
- [Node.js] 프로그래머스 - 크레인 인형뽑기 게임
- [Node.js] 프로그래머스 - 기능개발
- [Rust] 백준 13717 - 포켓몬 GO
- [JavaScript] 백준 1092 - 배
- [Rust] 백준 25329 - 학생별 통화 요금 계산
기하학! 나는 기하학이 싫어
문제 설명
- 좌표 평면에 두 터렛이 있고 좌표, 목표물의 거리를 알려준다 (x1, y1, r1, x2, y2, r2)
- 목표물이 위치할 수 있는 점의 개수를 찾으면 끝
접근
두 원의 교점의 개수를 생각하자.
두 원 중심 사이의 거리와, 두 반지름의 관계를 생각하면 해결된다. (많은 원을 그려서 파악…)
혹시 두 점 사이의 거리를 구하면 제곱은으로 인해 문제가 발생할 수 있으니 f64를 적용하긴 했는데.. (제곱하면 됐음)
경우는
- 완전 일치
- 멀리 떨어진 경우
- 내부에 하나가 그냥 포함된 경우
- 외부에서 만나는 경우
- 내부에서 한쪽으로 만나는 경우
- 두 점에서 만나는 경우
| 번호 | 교점 | 조건 |
|---|---|---|
| 1 | -1 | 거리 = 0, 반지름 같음 |
| 2 | 0 | 거리 > 두 반지름 합 |
| 3 | 0 | 거리가 반지름의 차보다 작음 |
| 4 | 1 | 거리 = 반지름 합 |
| 5 | 1 | 거리 = 반지름 차 |
| 6 | 2 | 위의 모든 조건을 통과한 경우 |
if 문으로 작성하기에 순서가 중요하다.
중요한 값들
- 거리 d^2 = (x1 - x2)^2 + (y1 - y2)^2
- 반지름의 합 제곱
- 반지름의 차 제곱
정답 코드
//! ## 백준 1002 (실버3) 터렛
//!
//! x1,y1,r1,x2,y2,r2
//!
//! [문제 링크](https://www.acmicpc.net/problem/1002)
use std::io::{self, BufWriter, Read, Write};
pub fn main() {
let mut input = String::new();
io::stdin()
.read_to_string(&mut input)
.expect("expected input");
let mut lines = input.lines();
let mut output = BufWriter::new(io::stdout().lock());
let t: usize = lines
.next()
.expect("expect T")
.trim()
.parse()
.expect("can not parse");
for _ in 0..t {
let info: Vec<isize> = lines
.next()
.unwrap()
.split_ascii_whitespace()
.map(|s| s.parse().unwrap())
.collect();
let x1 = info[0] as f64;
let y1 = info[1] as f64;
let r1 = info[2] as f64;
let x2 = info[3] as f64;
let y2 = info[4] as f64;
let r2 = info[5] as f64;
let res = get_location_cnt(x1, y1, r1, x2, y2, r2);
writeln!(output, "{}", res).expect("write failed");
}
}
fn get_location_cnt(x1: f64, y1: f64, r1: f64, x2: f64, y2: f64, r2: f64) -> isize {
// 거리 계산
let dx = x1 - x2;
let dy = y1 - y2;
let d_sq = dx * dx + dy * dy;
// 반지름 합 / 차 제곱
let r_sum_sq = (r1 + r2) * (r1 + r2);
let r_diff_sq = (r1 - r2) * (r1 - r2);
// 완전 일치
if d_sq < 1e-9 && r1 == r2 {
return -1;
}
// 멂
if d_sq > r_sum_sq {
return 0;
}
// 내부에 있고 만나진 않음
if d_sq < r_diff_sq {
return 0;
}
// 내접 (1개)
if (d_sq - r_sum_sq).abs() < 1e-9 {
return 1;
}
// 외접
if (d_sq - r_diff_sq).abs() < 1e-9 {
return 1;
}
// 두 점 교차
2
}
마무리하며
아… 조건문 순서를 생각하면서 코드를 치려니 쉽지 않았다
그래도 간만에 좌표평면과 원을 직접 그려가면서 이것저것 생각해본 것은 신선한 자극이 아니었을까…
f64 안써도 됐을 것 같고.
뭐 어쨌든 해냈다!
화이팅화이팅
-뱅-
