閱讀302 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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



最後更新:2017-04-03 16:48:57

  上一篇:go ubantu係統Django安裝教程
  下一篇:go 使用DirectDraw直接顯示YUV視頻數據