4667 Building Fence 解题报告

题意:给n个圆和m个三角形,且保证互不相交,用一个篱笆把他们围起来,求最短的周长是多少。

解法1:在每个圆上均匀的取2000个点,求凸包周长就可以水过。

解法2:求出所有圆之间的外公切线的切点,以及过三角形每个顶点的的直线和圆的切点,和三角形的三个顶点。这些点做凸包确定篱笆边上的图形。凸包的边和圆弧之和即为所求。求圆弧长度的时候要判断是优弧还是劣弧。用叉积判断两个向量的方向关系即可。

 

//Time:218MS	
//Memory:860K
include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const double EPS = 1e-10;
const double PI = acos(-1.0);
const int MAXN = 55;

int dcmp(double x)
{
    if(fabs(x)<EPS) return 0;
    return x<0? -1:1;
}
double sqr(double x)
{
    return x*x;
}
struct Point{
    double x,y;
    bool tp;
    int id;
    Point(){}
    Point(double a,double b):x(a),y(b){}
    Point operator +(const Point &a)const{return Point(x+a.x,y+a.y);}
    Point operator -(const Point &a)const{return Point(x-a.x,y-a.y);}
    Point operator *(double k) const{return Point(x*k,y*k);}
    Point operator /(double k) const{return Point(x/k,y/k);}
    bool operator <(const Point &a)const
    {
        return dcmp(x-a.x)<0||(dcmp(x-a.x)==0&&dcmp(y-a.y)<0);
    }
    bool operator ==(const Point &a)const
    {
        return dcmp(x-a.x)==0&&dcmp(y-a.y)==0;
    }
    Point trunc(double d)
    {
        double dist(Point ,Point);
        double len = dist(*this,Point(0,0));
        return Point(x*d/len,y*d/len);
    }
    Point rotate(double a)
    {
        return Point(x*cos(a)-y*sin(a),y*cos(a)+x*sin(a));
    }
    void input(){scanf("%lf%lf",&x,&y);}
};
struct Circle{
    Point o;
    double r;
    Circle(){}
    Circle(Point a,double b):o(a),r(b){}
    double area(){return sqr(r)*PI;}
    double len(double ang){return r*ang;}
};
struct Tri{
    Point p[3];
};
typedef Point Vector;
double cross(Vector a,Vector b)
{
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b)
{
    return a.x*b.x+a.y*b.y;
}
double length(Vector a)
{
    return sqrt(dot(a,a));
}
double dist(Point a,Point b)
{
    return length(a-b);
}
double v_angle(Vector a,Vector b)
{
    return acos(dot(a,b)/length(a)/length(b));
}

int ConvexHull(Point *p, int n, Point *ch)
{
    sort(p, p+n);
    n = unique(p, p+n) - p;
    int m = 0;
    for(int i = 0; i < n; i++)
    {
        while(m > 1 && dcmp(cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) m--;
        ch[m++] = p[i];
    }
    int k = m;
    for(int i = n-2; i >= 0; i--)
    {
        while(m > k && dcmp(cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) m--;
        ch[m++] = p[i];
    }
    if(n > 1) m--;
    return m;
}
Vector rotate(Vector a,double rad)
{
    Vector c;
    c.x = a.x*cos(rad)-a.y*sin(rad);
    c.y = a.x*sin(rad)+a.y*cos(rad);
    return c;
}
void get_ocmt(Circle c1,Circle c2,Point &s1, Point &e1,Point &s2,Point &e2)
{
    double l = dist(c1.o,c2.o);
    double d = fabs(c1.r-c2.r);
    double theta = acos(d/l);
    //if(dcmp(c1.r-c2.r)>0) swap(c1,c2);
    Vector vec = c1.o-c2.o;
    vec = vec.trunc(c1.r);
    s1 = c1.o+rotate(vec,theta);
    s2 = c1.o+vec.rotate(-theta);
    vec = vec.trunc(c2.r);
    e1 = c2.o+vec.rotate(theta);
    e2 = c2.o+vec.rotate(-theta);
}
void get_pc(Circle c, Point p,Point &s1,Point &s2)
{
    Vector u = p-c.o;

    double dist = length(u);
    Point v = c.o+u/dist*c.r;
    double ang = PI/2-asin(c.r/dist);
    s1 = rotate(v-c.o,-ang)+c.o;
    s2 = rotate(v-c.o,ang)+c.o;
}
Point p[55*55*55],ch[55*55*55];
int main()
{
    //freopen("/home/qitaishui/code/in.txt","r",stdin);
    int n,m,pn,chn;
    Circle c[MAXN];
    Tri tri[MAXN];

    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i = 0; i < n;i++)
        {
            c[i].o.input();
            scanf("%lf",&c[i].r);
        }
        if(n==1&&m==0)
        {
            printf("%.6f\n",c[0].len(2*PI));
            continue;
        }
        for(int i = 0; i < m; i++)
            for(int j = 0; j < 3; j++)
                tri[i].p[j].input();
        pn = 0;
        for(int i = 0; i < n; i++)
            for(int j = i+1; j < n; j++)
            {
                if(dcmp(c[i].r-c[j].r)>0)
                    get_ocmt(c[j],c[i],p[pn+1],p[pn],p[pn+3],p[pn+2]);
                else
                    get_ocmt(c[i],c[j],p[pn],p[pn+1],p[pn+2],p[pn+3]);
                p[pn].tp = 0,p[pn].id = i;
                p[pn+1].tp = 0,p[pn+1].id = j;
                p[pn+2].tp = 0,p[pn+2].id = i;
                p[pn+3].tp = 0,p[pn+3].id = j;
                pn+=4;
            }
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                for(int k = 0; k <3; k++)
                {
                    get_pc(c[i],tri[j].p[k],p[pn],p[pn+1]);
                    p[pn].tp = 0,p[pn].id = i;
                    p[pn+1].tp = 0,p[pn+1].id = i;
                    pn+=2;
                }

        for(int j = 0; j < m; j++)
            for(int k = 0; k <3; k++)
            {
                p[pn] = tri[j].p[k];
                p[pn].tp = 1, p[pn].id = j;
                pn++;
            }

        chn = ConvexHull(p,pn,ch);
        //cout<<chn<<endl;
        int top=0;
        bool flag = 0;
        double ans = 0,cir=0;
        for(int i = 0; i <chn; i++)
        {
            if(ch[i].tp==0&&ch[(i+1)%chn].tp==0&&ch[i].id==ch[(i+1)%chn].id)
            {
                int tmp=ch[i].id;
                double ang;
                ang = v_angle(ch[i]-c[tmp].o,ch[(i+1)%chn]-c[tmp].o);
                if(dcmp(cross(ch[i]-c[tmp].o,ch[(i+1)%chn]-c[tmp].o))<0)
                    ang = 2*PI-ang;
                ans=ans+c[tmp].len(ang);
            }
            else
                ans+=length(ch[i]-ch[(i+1)%chn]);
        }

        printf("%.6f\n",ans);
    }
    return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值