HDU 4667 精度+凸包+圆切线

简介:

题意:给出n个圆 m个三角形求一个最短距离把平面上的这两种图形包围住。


基本思想就是求出所有的“关键点”。将两圆两两求外切线,得到所有切点;将圆和三角形的
三个点依次做切线,也得到切点;加上所有三角形的三个点。
对这些点用Graham 求凸包,对于凸包上的每条边,如果它们在同一个圆上,用等价的圆弧替
代即可。

这题重要的不是思路而是精度。eps要再求凸包时起到明显作用,不然求出的周长误差特别大。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
using namespace std;
const double eps=1e-10;
const double pi=acos(-1.0);
struct point
{
    double x,y;
    int s,o;
    void input()
    {
        scanf("%lf%lf",&x,&y);
    }
};
struct triangle
{
    point a,b,c;
    void input()
    {
        a.s=b.s=c.s=-1;
        a.input(),b.input(),c.input();
    }
};
struct circle
{
    point center;
    double r;
    void input()
    {
        center.input(),scanf("%lf",&r);
    }
};
point data[100005],stack[100005],MinA;
triangle t[55];
circle c[55];
int top,num,n,m;
double Direction(point pi,point pj,point pk) //判断向量PiPj在向量PiPk的顺逆时针方向 +顺-逆0共线
{
    return (pj.x-pi.x)*(pk.y-pi.y)-(pk.x-pi.x)*(pj.y-pi.y);
}
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double Dis(point a,point b)
{
    double ret=dis(a,b);
    if(a.s!=-1&&a.s==b.s)
    {
        int i=a.s;
        double a1=atan2(a.y-c[i].center.y,a.x-c[i].center.x),a2=atan2(b.y-c[i].center.y,b.x-c[i].center.x);
        a2-=a1;
        if(a2<0)
            a2+=2*pi;
        return a2*c[i].r;
    }
    return ret;
}
bool cmp(point a,point b)
{
    double k=Direction(MinA,a,b);
    if(k>0) return 1;
    if(k<0) return 0;
    return Dis(MinA,a)>Dis(MinA,b);
}
void Graham_Scan(point *a,int numa)
{
    for(int i=0; i<numa; i++)
        if(a[i].y<a[0].y||(a[i].y==a[0].y&&a[i].x<a[0].x))
            swap(a[i],a[0]);
    MinA=a[0],top=0;
    sort(a+1,a+numa,cmp);
    stack[top++]=a[0],stack[top++]=a[1],stack[top++]=a[2];
    for(int i=3; i<numa; i++)
    {
        while(Direction(stack[top-2],stack[top-1],a[i])<=eps&&top>=2)
            top--;
        stack[top++]=a[i];
    }
}
void pointcircle(point a,circle c,int i)
{
    double a1=atan2(a.y-c.center.y,a.x-c.center.x),a2=acos(c.r/dis(a,c.center));
    data[num].o=-1,data[num].s=i,data[num].x=c.center.x+c.r*cos(a1+a2),data[num++].y=c.center.y+c.r*sin(a1+a2);
    data[num].o=-1,data[num].s=i,data[num].x=c.center.x+c.r*cos(a1-a2),data[num++].y=c.center.y+c.r*sin(a1-a2);
}
void get1(triangle t,circle c,int i)
{
    pointcircle(t.a,c,i);
    pointcircle(t.b,c,i);
    pointcircle(t.c,c,i);
}
void get2(circle a,circle b,int i,int j)
{
    double d1=dis(a.center,b.center),d2=fabs(a.r-b.r),a1,a2;
    a1=atan2(b.center.y-a.center.y,b.center.x-a.center.x);
    a2=acos(d2/d1);
    data[num].o=0,data[num].s=i,data[num].x=a.center.x+a.r*cos(a1+a2),data[num++].y=a.center.y+a.r*sin(a1+a2);
    data[num].o=0,data[num].s=i,data[num].x=a.center.x+a.r*cos(a1-a2),data[num++].y=a.center.y+a.r*sin(a1-a2);
    data[num].o=0,data[num].s=j,data[num].x=b.center.x+b.r*cos(a1+a2),data[num++].y=b.center.y+b.r*sin(a1+a2);
    data[num].o=0,data[num].s=j,data[num].x=b.center.x+b.r*cos(a1-a2),data[num++].y=b.center.y+b.r*sin(a1-a2);
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        num=0;
        for(int i=0; i<n; i++)
            c[i].input();
        for(int i=0; i<m; i++)
            t[i].input();
        if(n==1&&m==0)
        {
            printf("%.10f\n",2*pi*c[0].r);
            continue;
        }
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                if(i==j)continue;
                get2(c[i],c[j],i,j);
            }
        for(int i=0; i<m; i++)
            for(int j=0; j<n; j++)
                get1(t[i],c[j],j);
        for(int i=0; i<m; i++)
            data[num++]=t[i].a,data[num++]=t[i].b,data[num++]=t[i].c;
        Graham_Scan(data,num);
        double ans=0;
        for(int i=0; i<top; i++)
            ans+=Dis(stack[i],stack[(i+1)%top]);
        printf("%.10f\n",ans);
    }
    return 0;
}



目录
相关文章
|
4月前
|
算法
[Halcon&拟合] 直线、矩形和圆的边缘提取
[Halcon&拟合] 直线、矩形和圆的边缘提取
120 0
|
机器学习/深度学习 C++
C++实现实现逆时针旋转矩阵
C++实现实现逆时针旋转矩阵
C++实现实现逆时针旋转矩阵
|
10月前
|
算法
巧解“求取矩形面积划分”
巧解“求取矩形面积划分”
72 0
切线方程和法线方程
切线方程和法线方程
|
算法
秒懂算法 | 计算几何:圆
计算几何的基础是点积和叉积,它们定义了向量的大小和方向的关系,是其他计算几何概念和算法的出发点。在点积和叉积的基础上,本篇重点介绍圆覆盖。 计算几何题目的代码大多繁琐冗长,因此掌握模板代码是学习计算几何的关键。本篇精心组织了经典的几何模板
18010 1
秒懂算法 | 计算几何:圆
【LeetCode】149. 直线上最多的点数
【LeetCode】149. 直线上最多的点数
【LeetCode】149. 直线上最多的点数
AcWing 604. 圆的面积
AcWing 604. 圆的面积
54 0
AcWing 604. 圆的面积
|
机器学习/深度学习
矩阵中的最大正方形
给定一个N*N的矩阵matrix,只有0和1两种值,返回边框全是1的最大正方形的边 长长度。
260 0
最大三角形面积 鞋带公式& 海伦公式
最大三角形面积 鞋带公式& 海伦公式
266 0