hdoj.5130 Signal Interference【计算几何+圆与多边形相交面积】 2015/08/17

Signal Interference

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 982    Accepted Submission(s): 638
Special Judge

Problem Description
Two countries A-Land and B-Land are at war. The territory of A-Land is a simple polygon with no more than 500 vertices. For military use, A-Land constructed a radio tower (also written as A), and it's so powerful that the whole country was under its signal. To interfere A-Land's communication, B-Land decided to build another radio tower (also written as B). According to an accurate estimation, for any point P, if the euclidean distance between P and B is no more than k (0.2 ≤ k < 0.8) times of the distance between P and A, then point P is not able to receive clear signals from A, i.e. be interfered. Your task is to calculate the area in A-Land's territory that are under B-Land's interference.
 

Input
There are no more than 100 test cases in the input.

In each test case, firstly you are given a positive integer N indicating the amount of vertices on A-Land's territory, and an above mentioned real number k, which is rounded to 4 digits after the decimal point.

Then N lines follow. Each line contains two integers x and y (|x|, |y| ≤ 1000), indicating a vertex's coordinate on A's territory, in counterclockwise or clockwise order.

The last two lines of a test case give radio tower A and B's coordinates in the same form as vertexes' coordinates. You can assume that A is not equal to B.
 

Output
For each test case, firstly output the case number, then output your answer in one line following the format shown in sample. Please note that there is a blank after the ':'.

Your solution will be accepted if its absolute error or relative error is no more than 10-6.

This problem is special judged.
 

Sample Input
  
  
4 0.5000 -1 -1 1 -1 1 1 -1 1 0 0 -1 0
 

Sample Output
  
  
Case 1: 0.2729710441
 

Source

注:仔细推敲会发现,此题其实是求圆与多边形相交面积,套模板即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;

const double eps = 1e-8;
const double PI = acos(-1.0);

int dcmp(double x){
    if( x > eps ) return 1;
    return x < -eps ? -1 : 0;
}

struct Point{
    double x,y;
    Point(){
        x = y = 0;
    }
    Point(double a,double b){
        x = a;y = b;
    }
    inline void input(){
        scanf("%lf%lf",&x,&y);
    }
    inline Point operator-(const Point &b)const{
        return Point(x - b.x,y - b.y);
    }
    inline Point operator+(const Point &b)const{
        return Point(x + b.x,y + b.y);
    }
    inline Point operator*(const double &b)const{
        return Point(x * b,y * b);
    }
    inline double dot(const Point &b)const{
        return x * b.x + y * b.y;
    }
    inline double cross(const Point &b,const Point &c)const{
        return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);
    }
    inline double Dis(const Point &b)const{
        return sqrt((*this-b).dot(*this-b));
    }
    inline bool InLine(const Point &b,const Point &c)const{ //三点共线
        return !dcmp(cross(b,c));
    }
    inline bool OnSeg(const Point &b,const Point &c)const{ //点在线段上,包括端点
        return InLine(b,c) && (*this - c).dot(*this - b) < eps;
    }
};

inline double min(double a,double b){
    return a < b ? a : b;
}
inline double max(double a,double b){
    return a > b ? a : b;
}
inline double Sqr(double x){
    return x * x;
}
inline double Sqr(const Point &p){
    return p.dot(p);
}

Point LineCross(const Point &a,const Point &b,const Point &c,const Point &d){
    double u = a.cross(b,c) , v = b.cross(a,d);
    return Point((c.x * v + d.x * u) / (u + v) , (c.y * v + d.y * u) / (u + v));
}

double LineCrossCircle(const Point &a,const Point &b,const Point &r,double R,Point &p1,Point &p2){
    Point fp = LineCross(r , Point(r.x+a.y-b.y , r.y+b.x-a.x) , a , b);
    double rtol = r.Dis(fp);
    double rtos = fp.OnSeg(a , b) ? rtol : min(r.Dis(a) , r.Dis(b));
    double atob = a.Dis(b);
    double fptoe = sqrt(R * R - rtol * rtol) / atob;
    if( rtos > R - eps ) return rtos;
    p1 = fp + (a - b) * fptoe;
    p2 = fp + (b - a) * fptoe;
    return rtos;
}

double SectorArea(const Point &r,const Point &a,const Point &b,double R){ //不大于180度扇形面积,r->a->b逆时针
    double A2 = Sqr(r - a) , B2 = Sqr(r - b) , C2 = Sqr(a - b);
    return R * R * acos( (A2 + B2 - C2) * 0.5 / sqrt(A2) / sqrt(B2)) * 0.5;
}

double TACIA(const Point &r,const Point &a,const Point &b,double R){
    double adis = r.Dis(a) , bdis = r.Dis(b);
    if( adis < R + eps && bdis < R + eps )
        return r.cross(a , b) * 0.5;
    Point ta , tb;
    if( r.InLine(a,b) ) return 0.0;
    double rtos = LineCrossCircle(a, b, r, R, ta, tb);
    if( rtos > R - eps )
        return SectorArea(r, a, b, R);
    if( adis < R + eps )
        return r.cross(a, tb) * 0.5 + SectorArea(r, tb, b, R);
    if( bdis < R + eps )
        return r.cross(ta, b) * 0.5 + SectorArea(r, a, ta, R);
    return r.cross(ta, tb) * 0.5 + SectorArea(r, tb, b, R) + SectorArea(r, a, ta, R);
}

const int MAXN = 505;
Point p[MAXN];

double SPICA(int n,Point r,double R){
    int i;
    double ret = 0 , if_clock_t;
    for( i = 0 ; i < n ; ++i ){
        if_clock_t = dcmp(r.cross(p[i], p[(i + 1) % n]));
        if( if_clock_t < 0 )
            ret -= TACIA(r, p[(i + 1) % n], p[i], R);
        else ret += TACIA(r, p[i], p[(i + 1) % n], R);
    }
    return fabs(ret);
}

double cx,cy,x0,x1,yy0,yy1,k;

int main(){
    int i , ans = 1 , n;
    while( ~scanf("%d %lf",&n,&k) ){
        for( i = 0 ; i < n ; ++i )
            p[i].input();
        scanf("%lf %lf",&x0,&yy0);
        scanf("%lf %lf",&x1,&yy1);
        Point circle = Point(-(x1-k*k*x0)/(k*k-1) , -(yy1-k*k*yy0)/(k*k-1));
        double R = (x1*x1+yy1*yy1 - k*k*x0*x0 - k*k*yy0*yy0) / (k*k-1);
        R += (circle.x*circle.x+circle.y*circle.y);
        R = sqrt(R);
        printf("Case %d: %.10lf\n",ans++,SPICA(n,circle,R));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值