链接:http://acm.hdu.edu.cn/showproblem.php?pid=4667

题意:给n个圆m个三角形,求包住它们所需的最小长度。

思路:比赛的时候只想到了三角形用凸包围一下,圆不知道怎么处理。暴力一点的方法呢,把圆均分成了2000个整点,然后求凸包,圆弧上的弧线也用折线替代,这样对精度有损,一开始分成1000个点的时候精度就不够,wa掉了,如果圆上的弧线还是算弧长的话,可能还是可以过的。解题报告上说的是求任意两圆的外切线,得到所有切点,三角形顶点和圆的切点,三角形的顶点来求凸包。

暴力:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200000;
const double eps=1e-10;
const double PI=acos(-1.0);
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {}
    bool operator < (const Point& a) const
    {
        if(a.x != x) return x < a.x;
        return y < a.y;
    }
};
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p)
{
    return Vector(A.x*p,A.y*p);
}
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
bool operator == (const Point& a,const Point& b)
{
    return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}
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 Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
double dist(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
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 && 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 && Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2]) <= 0)
            m--;
        ch[m++]=p[i];
    }
    if(n>1) m--;
    return m;
}

Point p[maxn],ch[maxn];
int num=2000;
int main()
{
    freopen("1002.in","r",stdin);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        double x,y,r;
        int cnt=0;
        while(n--)
        {
            scanf("%lf%lf%lf",&x,&y,&r);
            for(int i=0;i<num;i++)
                p[cnt++]=Point((x+r*cos(2*PI*i/num)),(y+r*sin(2*PI*i/num)));
        }
        while(m--)
        {
            for(int i=0;i<3;i++)
            {
                scanf("%lf%lf",&x,&y);
                p[cnt++]=Point(x,y);
            }
        }
        int k=ConvexHull(p,cnt,ch);
        double ans=0;
        for(int i=0;i<k;i++)
           ans+=dist(ch[i],ch[(i+1)%k]);
        printf("%.10lf\n",ans);
    }
    return 0;
}
View Code

 求切点:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#include<utility>
using namespace std;
const int maxn=30000;
const double eps=1e-10;
const double PI=acos(-1.0);
struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p)
{
    return Vector(A.x*p,A.y*p);
}
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return x<0?-1:1;
}
bool operator == (const Point& a,const Point& b)
{
    return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}
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 Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
double dist(Point a,Point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Circle
{
    Point c;
    double r;
    Circle(Point c=Point(0,0),double r=0):c(c),r(r) {}
    Point getpoint(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
}cir[50];
Point inPoint()
{
    double x,y;
    scanf("%lf%lf",&x,&y);
    return Point(x,y);
}
Circle inCircle()
{
    double x,y,r;
    scanf("%lf%lf%lf",&x,&y,&r);
    Point p=Point(x,y);
    return Circle(p,r);
}

Point tri[200];
int n,m,cnt;
pair<Point,int> p[maxn];

void cctangent(Circle A,Circle B,int i,int j)
{
    double d=dist(A.c,B.c);
    double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    double ang=acos((A.r-B.r)/d);
    p[cnt].first=A.getpoint(base+ang);p[cnt++].second=i;
    p[cnt].first=A.getpoint(base-ang);p[cnt++].second=i;
    p[cnt].first=B.getpoint(base+ang);p[cnt++].second=j;
    p[cnt].first=B.getpoint(base-ang);p[cnt++].second=j;
}
void pctangent(Point t,Circle C,int i)
{
    Vector u=C.c-t;
    double d=Length(u);
    double b=acos(C.r/d);
    double a=atan2(t.y-C.c.y,t.x-C.c.x);
    double ang1=a-b,ang2=a+b;
    p[cnt].first=Point(cos(ang1)*C.r,sin(ang1)*C.r)+C.c;p[cnt++].second=i;
    p[cnt].first=Point(cos(ang2)*C.r,sin(ang2)*C.r)+C.c;p[cnt++].second=i;
}
void keypoint()
{
    cnt=0;
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
            cctangent(cir[i],cir[j],i,j);
    for(int i=0;i<3*m;i++)
        for(int j=0;j<n;j++)
            pctangent(tri[i],cir[j],j);
    for(int i=0;i<3*m;i++)
    {
        p[cnt].first=tri[i];
        p[cnt++].second=-1;
    }
}
bool cmp(const pair<Point, int> &p1, const pair<Point, int> &p2) {
    return dcmp(p1.first.y - p2.first.y) == 0 ? p1.first.x < p2.first.x : p1.first.y < p2.first.y;
}
int ConvexHull() {
    int top = 0;
    static pair<Point, int> sk[maxn];
    sort(p + 1, p + 1 + cnt, cmp);
    top = 2, sk[1] = p[1], sk[2] = p[2];
    for (int i = 3; i <= cnt; ++i) {
        while (top >= 2 && dcmp(Cross(p[i].first - sk[top - 1].first, sk[top].first - sk[top - 1].first)) >= 0) --top;
        sk[++top] = p[i];
    }
    int ttop = top;
    for (int i = cnt - 1; i >= 1; --i) {
        while (top > ttop && dcmp(Cross(p[i].first - sk[top - 1].first, sk[top].first - sk[top - 1].first)) >= 0) --top;
        sk[++top] = p[i];
    }
    --top;
    for (int i = 0; i < top; ++i) p[i] = sk[i+1];
    return top;
}
void solve()
{
    int h=ConvexHull();
    double ans=0.;
//    for(int i=0;i<h;i++)
//        cout<<p[i].first.x<<" "<<p[i].first.y<<" "<<p[i].second<<endl;
    for(int i=0;i<h;i++)
    {
        if(p[i].second != -1 && p[i].second==p[(i+1)%h].second)
        {
            int k=p[i].second;
            Point p1,p2;
            p1=p[i].first-cir[k].c;
            p2=p[(i+1)%h].first-cir[k].c;
            double ang1=atan2(p1.y,p1.x),ang2=atan2(p2.y,p2.x);
            ang2-=ang1;
            if(ang2<0) ang2+=2*PI;//
            ans+=ang2*cir[k].r;
        }
        else ans+=dist(p[i].first,p[(i+1)%h].first);
    }
    printf("%.10lf\n",ans);
}
int main()
{
    freopen("1002.in","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;i++)
            cir[i]=inCircle();
        for(int i=0;i<3*m;i++)
            tri[i]=inPoint();
        if(n==1 && m==0)
           printf("%.10lf\n",2*PI*cir[0].r);
        else
        {
            keypoint();
            solve();
        }
    }
    return 0;
}
View Code

前几组数据的输出和给的标准数据一样,后面8组数据误差挺大的,wa了,不知道为什么。后面再做。

 posted on 2013-08-16 09:37  ∑求和  阅读(742)  评论(0编辑  收藏  举报