• [代码]ural 1913 Titan Ruins: Old Generators Are Fine Too


    Abstract

    ural 1913 Titan Ruins: Old Generators Are Fine Too

    implementation 几何 圆交

    Source

    http://acm.timus.ru/problem.aspx?space=1&num=1913

    Solution

    主要思路就是判断距离到某两个点是r,另一个点是2r的点。

    比赛时候用三分乱搞,大概是被卡了精度还是什么的,没有通过。

    赛后用圆交重写了一遍,一开始还是没通过。

    然后发现自己的圆交模板是针对面积问题的,单点的情况没有考虑清楚,乱改的时候改错了。大致就是处理圆覆盖的情况时,在预处理统计时算被覆盖了一次,在算两圆交点的时候又被统计了一次。还是没弄熟悉圆交的原理所致。

    Code

    #include <iostream>
    #include <cassert>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const double EPS = 1e-8;
    const double PI = acos(-1.0);
    
    inline int sgn(double x) {
        if (fabs(x)<EPS) return 0;
        return x>0?1:-1;
    }
    
    struct sp {
        double x, y;
        double pa;
        int cnt;
        sp() {}
        sp(double a, double b): x(a), y(b) {}
        sp(double a, double b, double c, int d): x(a), y(b), pa(c), cnt(d) {}
        bool operator<(const sp &rhs) const {
            if (sgn(pa-rhs.pa)==0) return cnt>rhs.cnt;
            return pa<rhs.pa;
        }
        void read() {scanf("%lf%lf", &x, &y);}
        void write() {printf("%.10f %.10f\n", x, y);}
    }t, s1, s2, p[5], e[20];
    double r, rad[5];
    int cover[5];
    
    sp operator*(double d, const sp &v) {
        return sp(d*v.x, d*v.y);
    }
    
    sp operator-(const sp &u, const sp &v) {
        return sp(u.x-v.x, u.y-v.y);
    }
    
    sp operator+(const sp &u, const sp &v) {
        return sp(u.x+v.x, u.y+v.y);
    }
    
    double dot(const sp &u, const sp &v) {
        return u.x*v.x+u.y*v.y;
    }
    
    double det(const sp &u, const sp &v) {
        return u.x*v.y-u.y*v.x;
    }
    
    double dis(const sp &u, const sp &v) {
        double dx = u.x-v.x;
        double dy = u.y-v.y;
        return sqrt(dx*dx+dy*dy);
    }
    
    double dissqr(const sp &u, const sp &v) {
        double dx = u.x-v.x;
        double dy = u.y-v.y;
        return dx*dx+dy*dy;
    }
    
    void write(sp u, sp v) {
        puts("Now we have enough power");
        u.write(); v.write();
    }
    
    bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) {
        double d = dis(u, v);
        if (sgn(d-(ru+rv))>0 || sgn(d-fabs(ru-rv))<=0) return 0;
        sp c = u-v;
        double ca, sa, cb, sb, csum, ssum;
    
        ca = c.x/d, sa = c.y/d;
        cb = (rv*rv+d*d-ru*ru)/(2*rv*d), sb = sqrt(1-cb*cb);
        csum = ca*cb-sa*sb;
        ssum = sa*cb+sb*ca;
        a = sp(rv*csum, rv*ssum);
        a = a+v;
    
        sb = -sb;
        csum = ca*cb-sa*sb;
        ssum = sa*cb+sb*ca;
        b = sp(rv*csum, rv*ssum);
        b = b+v;
    
        return 1;
    }
    
    bool cu(int N, sp p[], double r[], sp &res) {
        int i, j, k;
        memset(cover, 0, sizeof cover);
        for (i = 0; i < N; ++i)
            for (j = 0; j < N; ++j) {
                double rd = r[i]-r[j];
                if (i!=j && sgn(rd)>0 && sgn(dis(p[i], p[j])-rd)<=0)
                    cover[j]++;
            }
        sp a, b;
        for (i = 0; i < N; ++i) {
            int ecnt = 0;
            e[ecnt++] = sp(p[i].x-r[i], p[i].y, -PI, 1);
            e[ecnt++] = sp(p[i].x-r[i], p[i].y, PI, -1);
            for (j = 0; j < N; ++j) {
                if (j==i) continue;
                if (cirint(p[i], r[i], p[j], r[j], a, b)) {
                    e[ecnt++] = sp(a.x, a.y, atan2(a.y-p[i].y, a.x-p[i].x), 1);
                    e[ecnt++] = sp(b.x, b.y, atan2(b.y-p[i].y, b.x-p[i].x), -1);
                    if (sgn(e[ecnt-2].pa-e[ecnt-1].pa)>0) {
                        e[0].cnt++;
                        e[1].cnt--;
                    }
                }
            }
            sort(e, e+ecnt);
            int cnt = e[0].cnt;
            for (j = 1; j < ecnt; ++j) {
                if (cover[i]+cnt==N) {
                    double a = (e[j].pa+e[j-1].pa)/2;
                    res = p[i]+sp(r[i]*cos(a), r[i]*sin(a));
                    return 1;
                }
                cnt += e[j].cnt;
            }
        }
        return 0;
    }
    
    bool solve(const sp &o, const sp &u, const sp &v, double r) {
        p[0] = o, rad[0] = r+r;
        p[1] = u; p[2] = v; rad[1] = rad[2] = r;
        sp a, b;
        if (cu(3, p, rad, a)) {
            b = 0.5*(a-o);
            b = o+b;
            write(a, b);
            return 1;
        }
        else return 0;
    }
    
    int main() {
        cin>>r;
        t.read(); s1.read(); s2.read();
        sp a, b, c, d;
        if (cirint(s1, r, s2, r, a, b)) {
            if (solve(t, s1, s2, r)) return 0;
        }
        else {
            if (cirint(s1, r, t, r, a, b) && cirint(s2, r, t, r, c, d)) {
                write(a, c);
                return 0;
            }
            else {
                if (solve(s1, t, s2, r)) return 0;
                if (solve(s2, t, s1, r)) return 0;
            }
        }
        puts("Death");
        return 0;
    }

    顺便贴圆交模板,这回的应该没问题了。

    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    const double PI = acos(-1.0);
    const double EPS = 1e-8;
    
    int sgn(double d) {
        if (fabs(d)<EPS) return 0;
        return d>0?1:-1;
    }
    
    struct sp {
        double x, y;
        double pa;
        int cnt;
        sp() {}
        sp(double a, double b): x(a), y(b) {}
        sp(double a, double b, double c, int d): x(a), y(b), pa(c), cnt(d) {}
        bool operator<(const sp &rhs) const {
            /* 需要处理单点的情况时
            if (sgn(pa-rhs.pa)==0) return cnt>rhs.cnt;
            */
            return pa<rhs.pa;
        }
        void read() {scanf("%lf%lf", &x, &y);}
        void write() {printf("%lf %lf\n", x, y);}
    };
    
    sp operator+(const sp &u, const sp &v) {
        return sp(u.x+v.x, u.y+v.y);
    }
    
    sp operator-(const sp &u, const sp &v) {
        return sp(u.x-v.x, u.y-v.y);
    }
    
    double det(const sp &u, const sp &v) {
        return u.x*v.y-v.x*u.y;
    }
    
    double dir(const sp &p, const sp &u, const sp &v) {
        return det(u-p, v-p);
    }
    
    double dis(const sp &u, const sp &v) {
        double dx = u.x-v.x;
        double dy = u.y-v.y;
        return sqrt(dx*dx+dy*dy);
    }
    
    //计算两圆交点
    //输入圆心坐标和半径
    //返回两圆是否相交(相切不算)
    //如果相交,交点返回在a和b(从a到b为u的交弧)
    bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) {
        double d = dis(u, v);
        /* 需要处理单点的情况时 覆盖的情况在这里不统计
        if (sgn(d-(ru+rv))>0 || sgn(d-fabs(ru-rv))<=0) return 0;
        */
        if (sgn(d-(ru+rv))>=0 || sgn(d-fabs(ru-rv))<=0) return 0;
        sp c = u-v;
        double ca, sa, cb, sb, csum, ssum;
    
        ca = c.x/d, sa = c.y/d;
        cb = (rv*rv+d*d-ru*ru)/(2*rv*d), sb = sqrt(1-cb*cb);
        csum = ca*cb-sa*sb;
        ssum = sa*cb+sb*ca;
        a = sp(rv*csum, rv*ssum);
        a = a+v;
    
        sb = -sb;
        csum = ca*cb-sa*sb;
        ssum = sa*cb+sb*ca;
        b = sp(rv*csum, rv*ssum);
        b = b+v;
    
        return 1;
    }
    
    sp e[222];
    int cover[111];
    
    //求圆并
    //输入点数N,圆心数组p,半径数组r,答案数组s
    //s[i]表示被至少i个圆覆盖的面积(最普通的圆并就是s[1])
    void circle_union(int N, sp p[], double r[], double s[]) {
        int i, j, k;
        memset(cover, 0, sizeof cover);
        for (i = 0; i < N; ++i)
            for (j = 0; j < N; ++j) {
                double rd = r[i]-r[j];
                //覆盖的情况在这里统计
                if (i!=j && sgn(rd)>0 && sgn(dis(p[i], p[j])-rd)<=0)
                    cover[j]++;
            }
        for (i = 0; i < N; ++i) {
            int ecnt = 0;
            e[ecnt++] = sp(p[i].x-r[i], p[i].y, -PI, 1);
            e[ecnt++] = sp(p[i].x-r[i], p[i].y, PI, -1);
            for (j = 0; j < N; ++j) {
                if (j==i) continue;
                if (cirint(p[i], r[i], p[j], r[j], a, b)) {
                    e[ecnt++] = sp(a.x, a.y, atan2(a.y-p[i].y, a.x-p[i].x), 1);
                    e[ecnt++] = sp(b.x, b.y, atan2(b.y-p[i].y, b.x-p[i].x), -1);
                    if (sgn(e[ecnt-2].pa-e[ecnt-1].pa)>0) {
                        e[0].cnt++;
                        e[1].cnt--;
                    }
                }
            }
            sort(e, e+ecnt);
            int cnt = e[0].cnt;
            for (j = 1; j < ecnt; ++j) {
                double pad = e[j].pa-e[j-1].pa;
                s[cover[i]+cnt] += (det(e[j-1], e[j])+r[i]*r[i]*(pad-sin(pad)))/2;
                cnt += e[j].cnt;
            }
        }
    }
  • 相关阅读:
    Coolite comboBox控件动态显示树形结构(无限树)
    WinXP 允许搜索PHP格式
    LINQ To DataSet 几个常用示例
    在Windows系统上安装PHP工作环境
    将LINQ To DataSet 传回之对象集转成DataTable的函数
    .net wsdl文件用法
    上班了,抱怨一下
    写在情人节
    快乐云南行
    单车骑天下 VS 公益旅游活动
  • 原文地址:https://www.cnblogs.com/jffifa/p/2734461.html
Copyright © 2020-2023  润新知