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;
}

​

猜你喜欢

转载自blog.csdn.net/qq_18869763/article/details/83958623
two
今日推荐