2015 北京网络赛 E Border Length hihoCoder 1231 树状数组 (2015-11-05 09:30)

#1231 : Border Length

时间限制:1000ms
单点时限:1000ms
内存限制:256MB

描述

Garlic-Counting Chicken is a special species living around the Lake of Peking University.

A Garlic-Counting Chicken always flies out from home in the morning, goes to some fixed points looking for buuugs(a kind of worm), and comes back home in the afternoon.

Students from the School of Life Sciences find that, a Garlic-Counting Chicken always flies a straight line between two points, and its trace never goes across itself. The students want to find out the relationship between Garlic-Counting Chicken and the Lake. So they ask you to calculate the length of border of the common area between the Lake and one Garlic-Counting Chicken's daily trace.

输入

There are no more than 10 test cases.

For each test case, the first line contains n, the number of points on the trace in order. 1<=n<=1000.

Then n lines follow. Each line is a pair of integer x, y representing the n points' coordinates in order.

The last line contains three integers x,y and r  descripting the Lake, The Lake is a circle. Its center is at (x,y) and its radius is r.  

The input ends if n = 0.

All |x|, |y|, |r| are smaller than 107.

输出

For each test case, output the length of the border of the common area. Please round the answer to the closest integer.

样例输入
4
-10 -10
-10 10
10 10
10 -10
-10 -10 20
4
-10 -10
-10 10
10 10
10 -10
-10 -10 4
4
-10 -10
-10 10
10 10
10 -10
0 0 10
4
-40 -40
-40 40
40 40
40 -40
0 0 50
0
样例输出
71
14
63
297
这样比较 好写,也好理解,但是还是写了挺长的代码

 

#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <cstdio>
using namespace std;
const double eps=0.000000000001;
const double PI=acos(-1.0);
const int maxn=3005;
int dcmp(double a)
{
    if(fabs(a)<eps)return 0;
    else return a>0?1:-1;
}
struct Point
{
  double x,y;
  Point(double cx=0,double cy=0)
  {
      x=cx; y=cy;
  }
  double ang;
  void Angle()
  {
      ang=atan2(y,x);
      if(ang<0){
        ang+=2*PI;
      }
  }
  bool operator <(const Point &rhs)const
  {
     return ang<rhs.ang;
  }
};
struct Circle
{
    Point c;
    double r;
    Circle(Point cc=Point(0,0),double cr=0)
    {
        c=cc; r=cr;
    }
    Point point(double a)
    {
        return Point(c.x+cos(a)*r, c.y+sin(a)*r);
    }
};
Point operator -(Point A, Point B)
{
    return Point(A.x-B.x,A.y-B.y);
}
Point operator +(Point A, Point B)
{
    return Point(A.x+B.x,A.y+B.y);
}
bool operator ==(const Point &A, const Point &B)
{
    return dcmp(A.x-B.x) == 0&& dcmp(A.y-B.y)==0;
}
double Dot(Point A,Point B)
{
    return A.x*B.x+A.y*B.y;
}
double Length(Point A)
{
     return sqrt(Dot(A,A));
}
double Cross(Point A, Point B)
{
    return A.x*B.y - A.y*B.x;
}
Point TE[maxn];
Circle C;
struct Ins{
  Point c;
  int id;
}Poi[maxn];
struct Line
{
    Point p;
    Point v;
    Line(Point cp=Point(0,0),Point cv=Point(0,0))
    {
        p=cp; v=cv;
    }
    Point point(double a)
    {
        Point te=Point(v.x*a,v.y*a);
        return p+te;
    }
};
int getLineCicleIntersection(Line L,Circle C, double &t1,double &t2,Point &A,Point &B)
{
    double a=L.v.x,
           b=L.p.x-C.c.x,
           c=L.v.y,
           d=L.p.y-C.c.y;
    double e=a*a+c*c,
           f=2*(a*b+c*d),
           g=b*b+d*d-C.r*C.r;
    double delta=f*f-4*e*g;
    if(dcmp(delta)<0)return 0;
    if(dcmp(delta)==0)
    {
        t1=t2=-f/(2*e);A=L.point(t1);
        return 1;
    }
    t1=(-f - sqrt(delta))/(2*e);
    A=L.point(t1);
    t2=(-f + sqrt(delta))/(2*e);
    B=L.point(t2);
    return 2;
}
int judjiaodian(int n)
{
     int nu=0;
     double t1,t2;
     Point A,B;
     for(int i=0; i<n; i++)
     {
         int ge=getLineCicleIntersection(Line(TE[i],TE[i+1]-TE[i]),C,t1,t2,A,B);//计算直线和圆交点 大白书模板
           if(ge==0)continue;
           double s=Length(TE[i]-TE[i+1]);
           double d1=Length(TE[i]-A);
           double d2=Length(TE[i+1]-A);
          if(ge==1){
             if(dcmp(s-d1)>=0&&dcmp(s-d2)>=0) //判断是否在这条边上
             {
                   Poi[nu].c=A; Poi[nu].id=i; nu++;
             }
            continue;
          }
          double d3=Length(TE[i]-B);
          double d4=Length(TE[i+1]-B);
          if(dcmp(s-d1)>=0&&dcmp(s-d2)>=0&&dcmp(s-d3)>=0&&dcmp(s-d4)>=0)//如果存在两个点
            {
                 if(d1>d3){//应该把离起点进的点放在前面
                    swap(A,B);
                 }
                 Poi[nu].c=A; Poi[nu].id=i;nu++;
                 Poi[nu].c=B; Poi[nu].id=i;nu++;
            }else if(dcmp(s-d1)>=0&&dcmp(s-d2)>=0)
            {
                 Poi[nu].c=A; Poi[nu].id=i;nu++;
            }else if(dcmp(s-d3)>=0&&dcmp(s-d4)>=0)
            {
                 Poi[nu].c=B; Poi[nu].id=i;nu++;
            }
     }
     int ge=1;
     for(int i=1; i<nu; i++)
        if( (Poi[i].c==Poi[ge-1].c) == false )
         Poi[ge++]=Poi[i];
     nu=ge;
     return nu;
}
int isPointInpolygon(Point p,int n)//判断点是否在多边形内
{
    int wn=0;
    for(int i=0; i<n; i++)
    {
        int k=dcmp(Cross(TE[i+1]-TE[i],p-TE[i]));
        int d1=dcmp(TE[i].y -p.y );
        int d2=dcmp(TE[i+1].y-p.y);
        if( k > 0 && d1 <= 0 && d2 > 0 )wn++;
        if( k < 0 && d2 <= 0 && d1 >0  )wn--;
     }
     if(wn!=0)return 1;
     return 0;
}
void solve(int n)
{
    int numOfInCir=0;
    double dist=0;
    for(int i=0; i<n; i++)
        {
            if( dcmp( C.r-Length(TE[i]-C.c) )>=0 )numOfInCir++;
            dist+=Length( TE[i+1]-TE[i] );
        }
    if(isPointInpolygon(C.c,n))
    {
        if(numOfInCir==n){
            printf("%.0lf\n",dist);
        }else printf("%.0lf\n",PI*2*C.r);
        return;
    }
    if(numOfInCir == n)
    {
            printf("%.0lf\n",dist);
    }else printf("0\n");
}
Point Hu[maxn];
double judsolveCir(int nu,int n)
{
    for(int i=0; i<nu; i++)
    {
        Hu[i]=Poi[i].c-C.c;
        Hu[i].Angle();
    }
    sort(Hu,Hu+nu);
    Hu[nu]=Hu[0];
    Hu[nu].ang+=2*PI;
    double ans=0;
    for(int i=0; i<nu; i++)
    {
        double ang=(Hu[i].ang+Hu[i+1].ang)/2;
        if(ang>2*PI)ang-=2*PI;
        Point t =C.point(ang);
        if(isPointInpolygon(t,n))
        {
           ang=Hu[i+1].ang-Hu[i].ang;
           ans+=ang*C.r;
        }
    }
    return ans;
}
Point TP[maxn];
double judsolvePoly(int nu, int n)
{
   int loc=0,num=0;
   for(int i=0; i<n; i++)//融合那些点
   {
       TP[num++]=TE[i];
       while(loc<nu&&Poi[loc].id<=i){
         TP[num++]=Poi[loc].c; loc++;
       }
   }
   loc=1;
   for(int i=1; i<num; i++)
    if((TP[i]==TP[loc-1])==false )TP[loc++]=TP[i];
   num=loc;
   TP[num]=TP[0];
   double ans=0;
   for(int i=0; i<num; i++)
   {
       Point tt=TP[i]+TP[i+1];
       tt.x*=0.5;
       tt.y*=0.5;
       double d1=Length(C.c-tt);
       if(dcmp(C.r-d1)>=0){
         ans+=Length(TP[i+1]-TP[i]);
       }
   }
   return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1&&n)
    {
        for(int i=0; i<n; i++)
            scanf("%lf%lf",&TE[i].x,&TE[i].y);
            TE[n]=TE[0];
        scanf("%lf%lf%lf",&C.c.x,&C.c.y,&C.r);
        int nu=judjiaodian(n);//计算交点
        if(nu==0||nu==1){
           solve(n);// 特判那几种情况
           continue;
        }
        double ans=judsolveCir(nu,n);// 计算圆在多边形内的部分
        ans+=judsolvePoly(nu,n);// 计算多边形在圆内的部分
        printf("%.0lf\n",ans);
    }
    return 0;
}
View Code

 

 

 

题意:

转载于:https://www.cnblogs.com/Opaser/p/4941080.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值