1. 程式人生 > >gym-100520 K. Kabbalah for Two

gym-100520 K. Kabbalah for Two

就是跟大白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;
}

​