HDU 4667 Building Fence(求凸包的周长)

题目链接:传送门 


题意:

给定n个圆,m个三角形求把这些图形全部覆盖的图形的最小的周长。


分析:

刚开始看到就想到了求凸包,可是圆怎么求了?就暴力把圆分割成1000个点然后求凸包就可以了。水过了,正解是找圆与圆的切点圆与三角形上的点与圆引得切线的切点。


代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;

typedef long long LL;

const double eps = 1e-10;

const int maxn = 1e6+10;

const double pi = acos(-1.0);

const double inf = 1e17;

int dcmp(double x){
    if(fabs(x)<eps) return 0;
    if(x>0) return 1;
    return -1;
}

struct point{
    double x,y;
    int id;
    point(){}
    point(double _x,double _y,int i):x(_x),y(_y),id(i){}
    bool operator <(const struct point &tmp)const{
        if(dcmp(x-tmp.x)==0) return dcmp(y-tmp.y)<0;
        return dcmp(x-tmp.x)<0;
    }
    bool operator == (const struct point &tmp)const{
        return dcmp(x-tmp.x)==0&&dcmp(y-tmp.y)==0;
    }
}p[maxn],st[maxn];

double Cross(point a,point b,point c){
    return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}

int ConvexHull(point *p,int n,point *st){
    sort(p,p+n);
    n=unique(p,p+n)-p;
    int m=0;
    for(int i=0; i<n; i++) {
        while(m>1&&Cross(st[m-2],p[i],st[m-1])<=0) m--;
        st[m++]=p[i];
    }
    int k=m;
    for(int i=n-2; i>=0; i--){
        while(m>k&&Cross(st[m-2],p[i],st[m-1])<=0)m--;
        st[m++]=p[i];
    }
    if(n>1) m--;
    return m;
}

double dis(point a,point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

int R[600];

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        int cnt = 0;
        for(int i=0;i<n;i++){
            double x,y,r;
            scanf("%lf%lf%lf",&x,&y,&r);
            R[i]=r;
            for(int j=0;j<1000;j++){
                double tmp = 2*pi*j/1000;
                p[cnt++]=point(x+r*cos(tmp),y+r*sin(tmp),i);
            }
        }
        for(int i=0;i<m*3;i++){
            double x,y;
            scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
            p[cnt].id=cnt++;
        }
        int num = ConvexHull(p,cnt,st);
        double ans = 0;
        for(int i=0;i<num;i++){
            int t1 = st[i].id;
            int t2 = st[(i+1)%num].id;
            if(t1==t2){
                ans+=pi*2*R[t1]/1000;
            }
            else ans+=dis(st[i],st[(i+1)%num]);
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值