码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-11-06 00:07:00      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:

#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

 

 

 

题意:

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

标签:

原文地址:http://www.cnblogs.com/Opaser/p/4941080.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!