ปัญหา: Circle and Rectangle Overlapping
กำหนดวงกลมด้วย (radius, xc, yc) โดย (xc, yc) คือศูนย์กลาง และสี่เหลี่ยมผืนผ้าที่ขนานแกน (axis-aligned) ด้วย (x1, y1, x2, y2) โดย (x1, y1) = มุมซ้ายล่าง, (x2, y2) = มุมขวาบน ตรวจสอบว่าทั้งสองรูปทับซ้อนกันหรือไม่
แนวคิดหลัก
หาจุดบนสี่เหลี่ยมที่อยู่ใกล้ศูนย์กลางวงกลมที่สุด (closest point) แล้วตรวจสอบระยะห่างจากจุดนั้นถึงศูนย์กลาง ว่าน้อยกว่าหรือเท่ากับรัศมีหรือไม่
ขั้นตอนการแก้
- ฟังก์ชัน
eval(a, b, c)– คืนค่าmax(b, min(a, c))ใช้ clamp ค่าระหว่างbและc - หาจุดใกล้ที่สุดบนสี่เหลี่ยม:
cdx = eval(cx, left, right)– พิกัด x ที่ clamp ระหว่าง left–rightcdy = eval(cy, bottom, top)– พิกัด y ที่ clamp ระหว่าง bottom–top
- คำนวณระยะห่างยกกำลังสอง:
dx = cx - cdx,dy = cy - cdydisSq = dx*dx + dy*dy
- เปรียบเทียบกับ
r*r– ถ้าdisSq <= r*r→ ทับซ้อน (true)
ตัวอย่างโค้ด C++
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int eval(int a, int b, int c) {
return max(b, min(a, c));
}
bool checkOverlap(int r, int cx, int cy,
int left, int bottom, int right, int top) {
double cdx = eval(cx, left, right);
double cdy = eval(cy, bottom, top);
double dx = cx - cdx;
double dy = cy - cdy;
double disSq = dx * dx + dy * dy;
double sqrRadius = r * r;
return disSq <= sqrRadius;
}
};
int main() {
Solution ob;
// r=1, center=(0,0), rect: left=1, bottom=-1, right=3, top=1
cout << ob.checkOverlap(1, 0, 0, 1, -1, 3, 1); // Output: 1 (true)
return 0;
}
อธิบายตัวอย่าง
วงกลมรัศมี 1 ศูนย์กลาง (0,0) สี่เหลี่ยมจาก (1,-1) ถึง (3,1)
- จุดบนสี่เหลี่ยมที่ใกล้ศูนย์กลางสุดคือ (1,0)
- ระยะห่าง = 1 → เท่ากับรัศมี → ทับซ้อนกัน
ความซับซ้อน
- เวลา: O(1) – คำนวณคงที่
- พื้นที่: O(1)
ข้อควรระวัง
- ใช้
doubleป้องกัน overflow เมื่อคำนวณกำลังสอง - ไม่ต้องแยกกรณีวงกลมอยู่ข้างใน/นอกสี่เหลี่ยม – สูตรครอบคลุมทุกกรณี
- กรณีขอบ (edge case): วงกลมสัมผัสขอบสี่เหลี่ยม → ถือว่าทับซ้อน