From 324111548a6ee25e797287555afc9488aa9ad50e Mon Sep 17 00:00:00 2001 From: minor7295 Date: Thu, 22 Jan 2026 23:04:26 +0900 Subject: [PATCH] =?UTF-8?q?BOJ=202166=20=EB=8B=A4=EA=B0=81=ED=98=95?= =?UTF-8?q?=EC=9D=98=20=EB=A9=B4=EC=A0=81=20=EB=AC=B8=EC=A0=9C=20=ED=92=80?= =?UTF-8?q?=EC=9D=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- computational-geometry/boj-2166/1.analysis.md | 119 ++++++ .../boj-2166/2.algorithm.md | 345 ++++++++++++++++++ .../boj-2166/3.reasoning.md | 194 ++++++++++ computational-geometry/boj-2166/Main.java | 52 +++ 4 files changed, 710 insertions(+) create mode 100644 computational-geometry/boj-2166/1.analysis.md create mode 100644 computational-geometry/boj-2166/2.algorithm.md create mode 100644 computational-geometry/boj-2166/3.reasoning.md create mode 100644 computational-geometry/boj-2166/Main.java diff --git a/computational-geometry/boj-2166/1.analysis.md b/computational-geometry/boj-2166/1.analysis.md new file mode 100644 index 0000000..22c755b --- /dev/null +++ b/computational-geometry/boj-2166/1.analysis.md @@ -0,0 +1,119 @@ +# 다각형의 면적 + +## 📌 문제 요약 + +2차원 평면상에 N개의 점으로 이루어진 다각형이 있다. 이 다각형의 면적을 구하는 프로그램을 작성하시오. + +--- + +## 🔍 문제 설명 + +* 2차원 좌표 평면 위에 N개의 점이 주어진다 +* 이 점들을 순서대로 이으면 다각형이 된다 +* 다각형의 면적을 구해야 한다 +* 면적은 소수점 아래 둘째 자리에서 반올림하여 첫째 자리까지 출력한다 + +--- + +## 📥 입력 조건 + +* 첫째 줄에 N이 주어진다 (3 ≤ N ≤ 10,000) +* 다음 N개의 줄에는 다각형을 이루는 순서대로 N개의 점의 x, y좌표가 주어진다 +* 좌표값은 절댓값이 100,000을 넘지 않는 정수이다 + +--- + +## 📤 출력 조건 + +* 첫째 줄에 면적을 출력한다 +* 면적을 출력할 때에는 소수점 아래 둘째 자리에서 반올림하여 첫째 자리까지 출력한다 + +--- + +### 📌 핵심 제약 조건 + +1. **다각형의 점 순서** + - 점들이 주어진 순서대로 이어져야 한다 + - 점의 순서가 바뀌면 다른 다각형이 될 수 있다 + +2. **좌표 범위** + - 모든 좌표는 정수 + - 범위: -100,000 ~ 100,000 + - 오버플로우 주의 필요 (int 범위를 넘을 수 있음) + +3. **면적 계산** + - 다각형이 시계 방향인지 반시계 방향인지에 따라 부호가 달라질 수 있다 + - 절댓값을 사용하여 항상 양수 면적을 구해야 한다 + +**예시 분석:** +``` +예제: 4개의 점 +(0, 0) → (0, 10) → (10, 10) → (10, 0) +→ 정사각형의 면적 = 10 × 10 = 100 +``` + +--- + +## ✨ 예시 + +### 예시 1 + +**입력** +``` +4 +0 0 +0 10 +10 10 +10 0 +``` + +**출력** +``` +100.0 +``` + +**설명**: +* 4개의 점 (0,0), (0,10), (10,10), (10,0)로 이루어진 정사각형 +* 면적 = 10 × 10 = 100 + +### 예시 2 (삼각형) + +**입력** +``` +3 +0 0 +4 0 +2 3 +``` + +**출력** +``` +6.0 +``` + +**설명**: +* 3개의 점으로 이루어진 삼각형 +* 밑변 4, 높이 3인 삼각형의 면적 = 4 × 3 / 2 = 6 + +--- + +## 📝 정리 + +이 문제는 **다각형의 면적을 구하는 계산 기하학 문제**로, 신발끈 공식(Shoelace Formula)을 활용하여 해결할 수 있다. + +**문제의 특징:** +- 입력 크기: N개의 점 (3 ≤ N ≤ 10,000) +- 시간 복잡도 O(N)으로 해결 가능 +- 계산 기하학의 기본 문제로, 다각형 면적 계산을 학습하기에 적합 + +**핵심 포인트:** +- 점들을 순서대로 이어서 다각형을 만든다 +- 신발끈 공식을 사용하여 면적을 계산한다 +- 면적은 항상 양수여야 하므로 절댓값을 사용한다 + +--- + +## 📚 관련 자료 + +> 📖 **계산 기하학 개요**: [../computational-geometry.md](../computational-geometry.md)를 참고하여 계산 기하학의 기본 개념과 다각형 면적 계산의 전반적인 이해를 돕습니다. + diff --git a/computational-geometry/boj-2166/2.algorithm.md b/computational-geometry/boj-2166/2.algorithm.md new file mode 100644 index 0000000..08ac3d7 --- /dev/null +++ b/computational-geometry/boj-2166/2.algorithm.md @@ -0,0 +1,345 @@ +# 알고리즘: 신발끈 공식(Shoelace Formula)을 이용한 다각형 면적 계산 + +> 📖 **문제 분석**: [1.analysis.md](./1.analysis.md)를 먼저 읽어보세요. +> 📖 **계산 기하학 개요**: [../computational-geometry.md](../computational-geometry.md)를 참고하여 다각형 면적 계산의 기본 개념을 이해하세요. + +이 문제는 **신발끈 공식(Shoelace Formula)**을 활용하여 다각형의 면적을 계산합니다. + +**알고리즘 분류**: 계산 기하학 (Computational Geometry) + +--- + +## 🧠 해결 전략 개요 + +### 1️⃣ 문제의식: 다각형의 면적을 어떻게 구할까? + +**직관적인 접근:** +- 삼각형의 면적은 쉽게 구할 수 있다 (밑변 × 높이 / 2) +- 하지만 다각형은 복잡한 모양일 수 있어서 직접 계산하기 어렵다 + +**핵심 질문:** +- "다각형을 여러 개의 삼각형으로 나눌 수 있을까?" +- "더 간단한 수학적 방법이 있을까?" + +### 2️⃣ 해결책: 신발끈 공식(Shoelace Formula) + +**신발끈 공식의 아이디어:** +- 다각형의 각 변을 이용하여 면적을 계산한다 +- 각 변과 원점을 연결한 사다리꼴의 넓이를 모두 더하면 다각형의 넓이가 된다 +- 마치 신발끈을 묶는 것처럼 좌표를 교차하여 계산한다 + +**해결 전략:** +1. **각 변에 대해 계산**: 다각형의 각 변 (P[i] → P[i+1])에 대해 특정 값을 계산 +2. **모두 더하기**: 계산한 값들을 모두 더한다 +3. **절댓값과 나누기**: 결과의 절댓값을 구하고 2로 나눈다 + +--- + +## 알고리즘 개요 + +### 📊 알고리즘 플로우차트 + +**전체 알고리즘 흐름:** + +```mermaid +flowchart TD + Start([시작]) --> Input["N개의 점 입력
P[0], P[1], ..., P[N-1]"] + + Input --> Init["면적 변수 초기화
area = 0"] + + Init --> Loop["i = 0부터 N-1까지 반복"] + + Loop --> Calc["각 변에 대해 계산
j = (i+1) % N
area += x[i] * y[j] - x[j] * y[i]"] + + Calc --> Check{"모든 점
처리했나?"} + + Check -->|아직 남음| Loop + Check -->|완료| Abs["절댓값 계산
area = |area|"] + + Abs --> Divide["2로 나누기
area = area / 2.0"] + + Divide --> Round["소수점 둘째 자리에서
반올림하여 첫째 자리까지"] + + Round --> Output["면적 출력"] + + Output --> End([종료]) + + style Start fill:#E3F2FD + style End fill:#C8E6C9 + style Loop fill:#FFF9C4 + style Calc fill:#FFE0B2 +``` + +**핵심:** +- 각 변에 대해 x[i] * y[j] - x[j] * y[i] 계산 +- 모두 더한 후 절댓값을 구하고 2로 나눔 +- O(N) 시간 복잡도 + +--- + +## 신발끈 공식의 직관적 이해 + +### 💡 왜 "신발끈" 공식이라고 부를까? + +**공식의 모양이 신발끈을 묶는 것처럼 보이기 때문입니다:** + +``` +점들: P0(x0, y0), P1(x1, y1), P2(x2, y2), ..., Pn-1(xn-1, yn-1) + +계산 과정: +x0 y0 + ↘ +x1 y1 + ↘ +x2 y2 + ↘ +... ... + ↘ +xn-1 yn-1 + ↘ +x0 y0 (다시 처음으로) + +이렇게 대각선으로 곱하면서 더하는 모양이 신발끈을 묶는 것처럼 보입니다! +``` + +### 💡 기하학적 의미: 사다리꼴 넓이의 합 + +**신발끈 공식은 사실 각 변과 원점을 연결한 사다리꼴의 넓이를 더한 것입니다:** + +``` +다각형: P0 → P1 → P2 → ... → Pn-1 → P0 + +각 변 P[i] → P[i+1]에 대해: +- 이 변과 원점(0,0)을 연결하면 사다리꼴이 생깁니다 +- 이 사다리꼴의 넓이 = (x[i] * y[i+1] - x[i+1] * y[i]) / 2 + +모든 변에 대해 이런 사다리꼴을 만들고 넓이를 더하면: +- 다각형의 넓이를 구할 수 있습니다! +``` + +**시각적 예시 (사각형):** + +``` +점: (0,0) → (0,10) → (10,10) → (10,0) + +각 변에 대한 사다리꼴: +1. (0,0) → (0,10): 넓이 = (0*10 - 0*0)/2 = 0 +2. (0,10) → (10,10): 넓이 = (0*10 - 10*10)/2 = -50 +3. (10,10) → (10,0): 넓이 = (10*0 - 10*10)/2 = -50 +4. (10,0) → (0,0): 넓이 = (10*0 - 0*0)/2 = 0 + +합: 0 + (-50) + (-50) + 0 = -100 +절댓값: 100 +나누기 2: 100 / 2 = 50... 아니다! + +실제로는: +합: 0*10 + 0*10 + 10*0 + 10*0 - (0*0 + 10*10 + 10*10 + 0*0) + = 0 + 0 + 0 + 0 - (0 + 100 + 100 + 0) + = -200 +절댓값: 200 +나누기 2: 200 / 2 = 100 ✅ +``` + +--- + +## 구현 패턴 + +**핵심 구현:** + +```java +// 신발끈 공식을 이용한 다각형 면적 계산 +static double polygonArea(long[] x, long[] y, int n) { + long area = 0; + + // 각 변에 대해 계산 + for (int i = 0; i < n; i++) { + int j = (i + 1) % n; // 다음 점 (마지막 점은 첫 번째 점과 연결) + area += x[i] * y[j] - x[j] * y[i]; + } + + // 절댓값을 구하고 2로 나눔 + return Math.abs(area) / 2.0; +} +``` + +**예시 (사각형: (0,0), (0,10), (10,10), (10,0)):** + +``` +i=0: j=1, area += 0*10 - 0*0 = 0 +i=1: j=2, area += 0*10 - 10*10 = -100 +i=2: j=3, area += 10*0 - 10*10 = -100 +i=3: j=0, area += 10*0 - 0*0 = 0 + +총합: 0 + (-100) + (-100) + 0 = -200 +절댓값: 200 +나누기 2: 200 / 2 = 100 ✅ +``` + +--- + +## 신발끈 공식의 수학적 배경 (간단한 설명) + +> 💡 **선형대수를 모르는 분들을 위한 설명**: 이 부분은 이해가 안 되면 넘어가셔도 됩니다. 공식만 외워서 사용해도 충분합니다! + +**신발끈 공식은 사실 외적(Cross Product)을 이용한 것입니다:** + +- 각 변 P[i] → P[i+1]은 벡터로 볼 수 있습니다 +- 이 벡터와 원점을 연결한 사다리꼴의 넓이는 외적과 관련이 있습니다 +- 모든 사다리꼴의 넓이를 더하면 다각형의 넓이가 됩니다 + +**하지만 이걸 몰라도 괜찮습니다!** +- 공식만 외워서 사용하면 됩니다 +- 각 변에 대해 `x[i] * y[j] - x[j] * y[i]`를 계산하고 +- 모두 더한 후 절댓값을 구하고 2로 나누면 됩니다 + +--- + +## 시간 복잡도 + +**전체 시간 복잡도: `O(N)`** + +**근거:** +- N개의 점을 입력받음: O(N) +- 각 점에 대해 한 번씩 계산: O(N) +- 출력: O(1) +- **총 시간 복잡도: O(N)** + +### ⏱️ 빅오 표기법과 실제 실행 시간의 관계 + +> 📖 **일반적인 시간 복잡도 평가 기준**: [COMPLEXITY_REFERENCE.md](../../../COMPLEXITY_REFERENCE.md)의 "시간 복잡도 평가 기준" 섹션을 참고하세요. + +#### BOJ 2166 문제의 경우 + +**문제 제약 조건:** +- 입력: N개의 점 (3 ≤ N ≤ 10,000) +- 시간 제한: 2초 + +**연산 횟수 계산:** + +1. **O(N) 알고리즘 (현재 방법):** + ``` + 입력: N줄 × 2개 정수 = 2N개 정수 읽기 + 면적 계산: N번의 곱셈과 뺄셈 + 출력: 1개 실수 + + N = 10,000일 때: + 총 연산 횟수: 약 20,000번 미만 + 예상 실행 시간: 거의 0초 ✅ (매우 빠름) + ``` + +**결론:** +- 시간 복잡도 O(N)으로 매우 빠르게 처리 가능 +- 상세한 시간 복잡도 평가 방법은 [COMPLEXITY_REFERENCE.md](../../../COMPLEXITY_REFERENCE.md)를 참고하세요 + +--- + +## 공간 복잡도 + +* **입력 저장**: O(N) (N개의 점의 좌표 저장) +* **계산 변수**: O(1) (면적 계산에 필요한 변수들) +* **전체 공간 복잡도**: **O(N)** + +### 💾 공간 복잡도 적합성 평가 + +> 📖 **일반적인 공간 복잡도 평가 기준**: [COMPLEXITY_REFERENCE.md](../../../COMPLEXITY_REFERENCE.md)의 "공간 복잡도 평가 기준" 섹션을 참고하세요. + +#### BOJ 2166 문제의 경우 + +**문제 제약 조건:** +- 메모리 제한: 128 MB + +**실제 메모리 사용량:** +- 입력 변수: N개 점 × 2개 좌표 × 8 bytes (long) = 16N bytes +- 계산 변수: 1개 long = 8 bytes +- **N = 10,000일 때: 약 160,008 bytes ≈ 160 KB** + +#### 메모리 제한과의 비교 + +**문제의 메모리 제한: 128 MB** + +- **사용 메모리: 약 160 KB** +- **사용률: 160 KB / 128 MB ≈ 0.12%** +- **결론: 메모리 제한 내에서 충분히 여유 있음 ✅** + +**결론:** +- 공간 복잡도 O(N)으로 효율적 +- 실제 메모리 사용량이 메모리 제한보다 훨씬 작음 +- 상세한 공간 복잡도 평가 방법은 [COMPLEXITY_REFERENCE.md](../../../COMPLEXITY_REFERENCE.md)를 참고하세요 + +--- + +## 이 문제의 특이사항 + +### 1️⃣ 오버플로우 주의 + +**문제 제약 조건:** +- 좌표 범위: -100,000 ~ 100,000 +- 계산 시 최대값: 100,000 × 100,000 = 10,000,000,000 +- int 범위: -2,147,483,648 ~ 2,147,483,647 +- **int로는 오버플로우 발생!** + +**해결책:** +```java +// long 타입 사용 +long area = 0; +area += (long)x[i] * y[j] - (long)x[j] * y[i]; +``` + +> 💡 **일반적인 주의사항**: 계산 기하학에서 오버플로우는 흔한 문제입니다. [../computational-geometry.md](../computational-geometry.md)의 "9️⃣ 계산 기하학 사용 시 주의사항" 섹션을 참고하세요. + +### 2️⃣ 절댓값 사용 + +**신발끈 공식의 결과:** +- 다각형이 시계 방향이면 음수 +- 다각형이 반시계 방향이면 양수 +- 하지만 면적은 항상 양수여야 함 + +**해결책:** +```java +return Math.abs(area) / 2.0; +``` + +**예시:** +- 시계 방향 다각형: area = -200 → |area| = 200 → 200/2 = 100 +- 반시계 방향 다각형: area = 200 → |area| = 200 → 200/2 = 100 +- 둘 다 같은 면적! + +### 3️⃣ 마지막 점과 첫 번째 점 연결 + +**다각형은 닫힌 도형이므로:** +- 마지막 점 P[N-1]과 첫 번째 점 P[0]도 연결되어야 함 +- 따라서 `j = (i + 1) % N`을 사용하여 순환 구조를 만듦 + +**예시:** +``` +점: P0, P1, P2, P3 +변: P0→P1, P1→P2, P2→P3, P3→P0 (마지막 변!) +``` + +### 4️⃣ 반올림 처리 + +**문제 요구사항:** +- 소수점 아래 둘째 자리에서 반올림하여 첫째 자리까지 출력 + +**해결책:** +```java +double area = polygonArea(x, y, n); +System.out.printf("%.1f\n", area); +// 또는 +System.out.println(String.format("%.1f", area)); +``` + +--- + +## 신발끈 공식의 활용 + +> 📖 **다각형 면적 계산의 다양한 활용**: [../computational-geometry.md](../computational-geometry.md)의 "패턴 3: 다각형의 넓이 계산" 섹션을 참고하세요. + +신발끈 공식은 다음과 같은 문제에서 활용됩니다: + +1. **다각형의 면적 계산**: 이 문제와 같이 다각형의 면적을 구할 때 +2. **다각형의 방향 판단**: 면적의 부호로 시계/반시계 방향 판단 +3. **다각형 내부 점 판단**: 점이 다각형 내부에 있는지 확인할 때 활용 + +> 💡 **구현 패턴**: 다각형 관련 문제의 구현 패턴은 [../computational-geometry.md](../computational-geometry.md)의 "8️⃣ 계산 기하학 구현 패턴" 섹션을 참고하세요. + diff --git a/computational-geometry/boj-2166/3.reasoning.md b/computational-geometry/boj-2166/3.reasoning.md new file mode 100644 index 0000000..e1bd0b1 --- /dev/null +++ b/computational-geometry/boj-2166/3.reasoning.md @@ -0,0 +1,194 @@ +# 알고리즘 선택 및 코드 설계 근거 + +이 문서는 **BOJ 2166 다각형의 면적 문제**에서 왜 이 알고리즘을 선택했는지, 그리고 코드가 어떻게 설계되었는지를 설명합니다. + +--- + +## 1️⃣ 알고리즘 선택 근거: 왜 "신발끈 공식(Shoelace Formula)"인가? + +> 📖 **알고리즘 상세 설명**: [2.algorithm.md](./2.algorithm.md)를 참고하세요. + +### 🔑 핵심 사고 과정: 다각형을 어떻게 나눌까? + +**왜 "신발끈 공식"이라는 접근을 했을까?** + +**핵심 사고 과정:** + +1. **목표: 다각형의 면적을 구하기** + - 문제: "N개의 점으로 이루어진 다각형의 면적은?" + - 하지만 다각형은 복잡한 모양일 수 있어서 직접 계산하기 어려움 + +2. **전략: 다각형을 여러 개의 도형으로 나누기** + - 삼각형으로 나누기: 다각형을 여러 삼각형으로 나눠서 각각의 넓이를 더하기 + - 사다리꼴로 나누기: 각 변과 원점을 연결한 사다리꼴의 넓이를 더하기 + - **신발끈 공식**: 사다리꼴 방법을 수식으로 간단하게 표현 + +3. **효율성** + - 시간 복잡도: O(N) (각 점을 한 번씩만 방문) + - 공간 복잡도: O(N) (점들의 좌표 저장) + - 매우 간단하고 효율적인 방법 + +--- + +### 🔍 다른 접근 방식과의 비교 + +**알고리즘을 결정할 때, 여러 방식 중에서 왜 "신발끈 공식"을 선택했을까?** + +#### 주요 접근 방식 요약 + +1. **삼각형으로 분할**: 다각형을 여러 삼각형으로 나눠서 각각의 넓이를 더하기 + - 복잡도: O(N) (삼각형 개수만큼) + - 구현 복잡도: 높음 (삼각형으로 나누는 로직 필요) + - 정확도: 높음 + +2. **사다리꼴로 분할**: 각 변과 원점을 연결한 사다리꼴의 넓이를 더하기 + - 복잡도: O(N) (변 개수만큼) + - 구현 복잡도: 중간 (사다리꼴 넓이 계산 필요) + - 정확도: 높음 + +3. **신발끈 공식 (현재 방식) ✅**: 사다리꼴 방법을 수식으로 간단하게 표현 + - 복잡도: O(N) (각 점을 한 번씩만 방문) + - 구현 복잡도: 낮음 (간단한 공식) + - 정확도: 높음 + +**왜 신발끈 공식을 선택했는가?** + +**핵심 이유:** +- ✅ **구현이 매우 간단**: 복잡한 분할 로직 없이 공식만 사용 +- ✅ **O(N) 시간 복잡도**: 매우 빠름 +- ✅ **정확함**: 수학적으로 정확한 결과 +- ✅ **표준 방법**: 계산 기하학에서 널리 사용되는 방법 +- ✅ **메모리 효율적**: 추가 자료구조 불필요 + +**결론:** +- 각 방식의 장단점을 고려한 결과 +- **"신발끈 공식"이 가장 적합함** +- 구현이 간단하고, 효율적이며, 계산 기하학의 표준 방법 + +--- + +## 2️⃣ 코드 설계 근거: 코드와 알고리즘의 1:1 대응 + +### ① 입력 처리 + +```java +int n = Integer.parseInt(br.readLine()); +long[] x = new long[n]; +long[] y = new long[n]; + +for (int i = 0; i < n; i++) { + st = new StringTokenizer(br.readLine()); + x[i] = Long.parseLong(st.nextToken()); + y[i] = Long.parseLong(st.nextToken()); +} +``` + +* **목적**: N개의 점의 좌표를 입력받음 +* **long 타입 사용**: 오버플로우 방지 (좌표 범위가 -100,000 ~ 100,000이므로 곱셈 시 int 범위 초과 가능) + +### ② 신발끈 공식 구현 + +```java +static double polygonArea(long[] x, long[] y, int n) { + long area = 0; + + for (int i = 0; i < n; i++) { + int j = (i + 1) % n; // 다음 점 (마지막 점은 첫 번째 점과 연결) + area += x[i] * y[j] - x[j] * y[i]; + } + + return Math.abs(area) / 2.0; +} +``` + +**왜 이렇게 구현했는가?** + +**핵심 이유: 신발끈 공식을 그대로 구현** + +1. **각 변에 대해 계산**: 다각형의 각 변 P[i] → P[i+1]에 대해 + - `x[i] * y[j] - x[j] * y[i]` 계산 + - 이는 해당 변과 원점을 연결한 사다리꼴의 넓이의 2배 + +2. **순환 구조**: 마지막 점과 첫 번째 점도 연결되어야 하므로 + - `j = (i + 1) % n`을 사용하여 순환 구조 구현 + +3. **절댓값과 나누기**: + - 면적은 항상 양수여야 하므로 `Math.abs(area)` 사용 + - 사다리꼴 넓이의 합이 실제 넓이의 2배이므로 `/ 2.0`으로 나눔 + +**경계 조건:** +* 모든 점을 정확히 한 번씩만 방문 +* 마지막 점과 첫 번째 점도 연결 +* long 타입 사용으로 오버플로우 방지 + +### ③ 반올림 처리 + +```java +double area = polygonArea(x, y, n); +System.out.printf("%.1f\n", area); +``` + +**문제 요구사항:** +- 소수점 아래 둘째 자리에서 반올림하여 첫째 자리까지 출력 +- `printf("%.1f", ...)`를 사용하여 자동으로 반올림 처리 + +--- + +## 3️⃣ 시간/공간 복잡도와 코드의 대응 + +> **시간/공간 복잡도 분석**: [2.algorithm.md](./2.algorithm.md)의 시간/공간 복잡도 섹션을 참고하세요. + +**코드와의 대응:** +- 시간 복잡도 O(N): 입력 읽기 O(N) + 면적 계산 O(N) + 출력 O(1) +- 공간 복잡도 O(N): 입력 변수 N개 점 × 2개 좌표 = O(N) + +--- + +## 4️⃣ 코드 최적화 고려사항 + +### 현재 구현의 특징 + +* **간단하고 명확함**: 알고리즘의 의도가 코드에 잘 드러남 +* **효율적**: O(N) 시간 복잡도 +* **정확함**: long 타입 사용으로 오버플로우 방지 +* **표준 방법**: 계산 기하학에서 널리 사용되는 방법 + +### 추가 최적화 가능성 + +* 입력 최적화: BufferedReader 사용 (이미 사용 중) +* 함수 분리: polygonArea 함수를 별도로 분리하여 재사용 가능하게 함 (이미 구현) +* 현재 구현이 문제 제약 조건 내에서 충분히 효율적 + +--- + +## 5️⃣ 정리 + +이 `Main.java`는 단순히 정답을 출력하는 코드가 아니라, + +* 계산 기하학의 **기본 도구인 신발끈 공식을 활용**하여 +* 알고리즘 문서에서 설명한 **다각형 면적 계산 알고리즘을 그대로 구현**하며 +* long 타입으로 **정확하고 효율적으로 동작**하는 + +**설계 의도가 드러나는 해답 코드**이다. + +즉, 설명 → 알고리즘 → 코드가 +**하나의 사고 흐름으로 완전히 일치**하도록 작성된 최종 결과물이다. + +--- + +## 6️⃣ 핵심 설계 원칙 + +1. **정확성**: long 타입 사용으로 오버플로우 방지 +2. **효율성**: O(N) 시간 복잡도로 최적화 +3. **명확성**: 코드만 봐도 알고리즘의 동작을 이해할 수 있음 +4. **일관성**: 알고리즘 문서의 설명과 코드가 1:1로 대응 +5. **표준성**: 계산 기하학에서 널리 사용되는 표준 방법 + +--- + +## 참고 + +* 문제 분석: [1.analysis.md](./1.analysis.md) +* 알고리즘 상세 설명: [2.algorithm.md](./2.algorithm.md) +* 계산 기하학 개요: [../computational-geometry.md](../computational-geometry.md) + diff --git a/computational-geometry/boj-2166/Main.java b/computational-geometry/boj-2166/Main.java new file mode 100644 index 0000000..9f81e11 --- /dev/null +++ b/computational-geometry/boj-2166/Main.java @@ -0,0 +1,52 @@ +import java.io.*; +import java.util.*; + +public class Main { + public static void main(String[] args) throws Exception { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + StringTokenizer st; + + // 점의 개수 입력 + int n = Integer.parseInt(br.readLine()); + + // 점들의 좌표 입력 + long[] x = new long[n]; + long[] y = new long[n]; + + for (int i = 0; i < n; i++) { + st = new StringTokenizer(br.readLine()); + x[i] = Long.parseLong(st.nextToken()); + y[i] = Long.parseLong(st.nextToken()); + } + + // 신발끈 공식을 이용한 다각형 면적 계산 + double area = polygonArea(x, y, n); + + // 소수점 둘째 자리에서 반올림하여 첫째 자리까지 출력 + System.out.printf("%.1f\n", area); + } + + /** + * 신발끈 공식(Shoelace Formula)을 이용한 다각형 면적 계산 + * + * @param x 점들의 x 좌표 배열 + * @param y 점들의 y 좌표 배열 + * @param n 점의 개수 + * @return 다각형의 면적 + */ + static double polygonArea(long[] x, long[] y, int n) { + long area = 0; + + // 각 변에 대해 계산 + for (int i = 0; i < n; i++) { + int j = (i + 1) % n; // 다음 점 (마지막 점은 첫 번째 점과 연결) + // 신발끈 공식: x[i] * y[j] - x[j] * y[i] + area += x[i] * y[j] - x[j] * y[i]; + } + + // 절댓값을 구하고 2로 나눔 + // (면적은 항상 양수여야 하므로 절댓값 사용) + return Math.abs(area) / 2.0; + } +} +