gym-100520 K. Kabbalah for Two
阿新 • • 發佈:2018-11-11
就是跟大白279頁的題有點類似的模版題而已。
#include"bits/stdc++.h" using namespace std; const int MX = 207; const double eps = 1e-12; int n; struct Point { double x, y; Point() {} Point(double x,double y):x(x),y(y) {} void read(){ scanf("%lf %lf",&x,&y); } void print(){ printf("%.12f %.12f\n",x,y); } }po[MX]; Point v[MX],v2[MX]; typedef Point Vector; int dcmp(double x) { //返回x的正負 if(fabs(x)<eps)return 0; return x<0?-1:1; } Vector operator-(Vector A,Vector B) {return Vector(A.x - B.x, A.y - B.y);} Vector operator+(Vector A,Vector B) {return Vector(A.x + B.x, A.y + B.y);} Vector operator*(Vector A,double p) {return Vector(A.x*p, A.y*p);} Vector operator/(Vector A,double p) {return Vector(A.x/p, A.y/p);} bool operator<(const Point&a,const Point&b) {return a.x<b.x||(a.x==b.x&&a.y<b.y);} bool operator==(const Point&a,const Point&b) {return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;} double Dot(Vector A,Vector B) { //點積 return A.x*B.x+A.y*B.y;//如果改成整形記得加LL } double Cross(Vector A,Vector B) { //叉積 return A.x*B.y-A.y*B.x;//如果改成整形記得加LL } //向量長度 double Length(Vector A) { return sqrt(Dot(A,A)); } //2個向量之間的夾角 double Angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B)); } //向量的極角 double angle(Vector v) { return atan2(v.y,v.x); } //計算ABC的有向面積 double Area(Point A,Point B,Point C) { return Cross(B-A,C-A)/2; } //將A向量逆時針旋轉rad Vector Rotate( Vector A,double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); } //返回A的逆時針旋轉90度的單位法向量 Vector Normal(Vector A) { double L=Length(A); return Vector(-A.y/L,A.x/L); } //有向線段 struct Line { Point p; Vector v;//方向向量,左邊為半平面 double ang;//極角 Line() {} Line(Point p,Vector v):p(p),v(v) { ang=atan2(v.y,v.x); } bool operator<(const Line &L)const { //極角排序 return ang<L.ang; } Point point(double t) { return p + v*t; } Line move(double d) { //向左邊平移d單位 return Line(p + Normal(v)*d, v); } }li[MX]; //計算2條直線P+tv和Q+tw的交點,請先確保不是平行(v!=w) Point GetLineIntersection(const Line& a, const Line& b) { Vector u = a.p-b.p; double t = Cross(b.v, u) / Cross(a.v, b.v); return a.p+a.v*t; } bool OnLeft(const Line& L, const Point& p){ return dcmp(Cross(L.v, p-L.p)) > 0; } // 半平面交主過程 //返回交平面點數 int HalfplaneIntersection(Line *L,int n,Point *ans){ sort(L, L+n); // 按極角排序 int first, last; // 雙端佇列的第一個元素和最後一個元素的下標 Point p[n]; // p[i]為q[i]和q[i+1]的交點 Line q[n]; // 雙端佇列 q[first=last=0] = L[0]; // 雙端佇列初始化為只有一個半平面L[0] for(int i = 1; i < n; i++){ while(first < last && !OnLeft(L[i], p[last-1])) last--; while(first < last && !OnLeft(L[i], p[first])) first++; q[++last] = L[i]; if(dcmp(Cross(q[last].v, q[last-1].v))==0) { // 兩向量平行且同向,取內側的一個 last--; if(OnLeft(q[last], L[i].p)) q[last] = L[i]; } if(first < last) p[last-1] = GetLineIntersection(q[last-1], q[last]); } while(first < last && !OnLeft(q[first], p[last-1])) last--; // 刪除無用平面 if(last - first <= 1) return 0; // 空集 p[last] = GetLineIntersection(q[last], q[first]); // 計算首尾兩個半平面的交點 // 從deque複製到輸出中 for(int i = first; i <= last; i++) ans[i-first]=p[i]; return last-first+1; } struct Circle { Point c; double r; Circle() {} Circle(Point c,double r):c(c),r(r) {} Point getpoint(double rad) { return Point(c.x+cos(rad)*r,c.y+sin(rad)*r); } }; int GetCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) { double d = Length(C1.c - C2.c); if(dcmp(d) == 0) { if(dcmp(C1.r - C2.r) == 0) return -1; // 重合,無窮多交點 return 0; } if(dcmp(C1.r + C2.r - d) < 0) return 0;//相離 if(dcmp(fabs(C1.r-C2.r) - d) > 0) return 0;//內含 double a = angle(C2.c - C1.c); double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d)); Point p1 = C1.getpoint(a-da), p2 = C1.getpoint(a+da); sol.push_back(p1); if(p1 == p2) return 1;//相切 sol.push_back(p2);//相交 return 2; } bool check(double r, Point &p1, Point &p2) { Point ploy[MX]; for(int i = 0; i < n; i++){ li[i] = Line(po[i]+v2[i]*r, v[i]); } int num = HalfplaneIntersection(li,n,ploy); vector<Point>sol; for(int i = 0; i < num; i++){ for(int j = i+1; j < num; j++){ if(GetCircleCircleIntersection(Circle(ploy[i],r),Circle(ploy[j],r),sol) == 0){ p1 = ploy[i]; p2 = ploy[j]; return 1; } } } return 0; } int main() { #ifdef LOCAL freopen("input.txt","r",stdin); #else freopen("kabbalah.in","r",stdin); freopen("kabbalah.out","w",stdout); #endif // LOCAL while(~scanf("%d",&n) && n){ for(int i = 0; i < n; i++){ po[i].read(); } po[n] = po[0]; for(int i = 0; i < n; i++){ v[i] = po[i+1]-po[i]; v2[i] = Normal(v[i]); } double l = 0, r = 1e5; Point p1,p2; for(int cnt = 0; cnt <= 70; cnt++){ double mid = (l+r)*0.5; if(check(mid,p1,p2)) l = mid; else r = mid; } printf("%.12f\n",l); p1.print(); p2.print(); } return 0; }