poj 1279 求半平面交的 面积
题目来源:
http://poj.org/problem?id=1279
分析: 求半平面交的 面积
代码如下:
const double EPS = 1e-8 ; const int Max_N = 1505 ; double add(double a, double b){ return (fabs(a + b) < EPS * (fabs(a) + fabs(b)) ) ? 0 : (a + b ); } struct Point { double x, y; Point(){} Point(double x, double y):x(x) , y(y){} Point operator - (Point a){ return Point(add(x , -a.x) , add(y , -a.y)) ; } Point operator + (Point a){ return Point(add(x , a.x) , add(y , a.y)) ; } double operator ^(Point a){ return add(x * a.y , - y * a.x) ; } Point operator * (double d){ return Point(x * d , y * d) ; } }; struct Line{ //有向直线 Point st, ed; Line(){} Line(Point s, Point e){ st = s ; ed = e ; } bool onRight(Point a){ //点a在直线向量的右边 return ((ed - st)^(a - st)) < 0 ; } bool parallel(Line l){ return ((ed -st)^(l.ed - l.st)) == 0 ; } Point Crossnode(Line l){ //两直线的交点 double t = (l.ed - l.st) ^(l.st - st) ; double t1 = (l.ed - l.st)^(ed - st) ; return st + (ed - st)*(t / t1) ; } double jijiao(){ return atan2(ed.y - st.y , ed.x - st.x) ; } void write(){ printf("%lf %lf %lf %lf\n" , st.x ,st.y ,ed.x ,ed.y) ; } }; //排序函数 [优先顺序:1极角 2. 前面的直线在后面的左边 ] bool operator < (Line l, Line r){ double lp = l.jijiao() ; double rp = r.jijiao() ; if( fabs(lp - rp) > EPS) return lp < rp ; return ((l.st - r.st)^(r.ed - r.st)) < -EPS ; } //用于计算的双端队列 Line dequeue[Max_N] ; Point pt[Max_N] ; // 返回半平面交的 交点 //获取 半平面交的 多边形(多边形的核) o(n log(2n)) //参数: 向量集合line[l], 向量数量[ln] (半平面方向在向量的左边) //函数运行后 如果n[即返回多边形的点数量] 为 0 则不存在半平面交的多边形(不存在区域或区域面积无穷大) int halfPanelCross(Line line[] , int ln){ int i, tn; sort(line, line + ln ) ; // 平面在向量左边 的筛选 for(i = tn = 1 ; i < ln ; i++){// 处理极角相同的,选择向量方向最左边的 if(fabs(line[i].jijiao() - line[i -1].jijiao()) > EPS) line[tn++] = line[i] ; } ln = tn ; int bot = 0 , top = 1 ; dequeue[0] = line[0] ; dequeue[1] = line[1] ; for(i = 2 ; i < ln ; i++){ if(dequeue[top].parallel(dequeue[top - 1])|| dequeue[bot].parallel(dequeue[bot + 1])) return 0 ; while(bot < top && line[i].onRight(dequeue[top].Crossnode(dequeue[top - 1]))) top -- ; while(bot < top && line[i].onRight(dequeue[bot].Crossnode(dequeue[bot + 1]))) bot ++ ; dequeue[++ top] = line[i] ; } while(bot < top && dequeue[bot].onRight(dequeue[top].Crossnode(dequeue[top -1]))) top -- ; while(bot < top && dequeue[top].onRight(dequeue[bot].Crossnode(dequeue[bot + 1]))) bot ++ ; if(top <= bot + 1) return 0 ; // 若队列为空, 则空集 int n = 0 ; //计算交点(注意不同直线形成的交点可能重合) 半平面交是凸多边形 for(i = bot ; i < top ; i++) pt[n ++] = dequeue[i].Crossnode(dequeue[i + 1]) ; if(bot < top +1) pt[n ++] = dequeue[bot].Crossnode(dequeue[top]) ; return n ; } Line List[Max_N] ; Point p[Max_N] ; int main(){ int t , i, j ; int m ; scanf("%d" , &t) ; while(t--){ scanf("%d" , &m) ; for(i = 0 ; i < m ; i++) scanf("%lf%lf" , &p[i].x , &p[i].y) ; for(i = 0 ; i < m ; i++){ List[i] = Line(p[(i + 1) % m] , p[i]) ; } int n = halfPanelCross(List , m) ; double area = 0.0 ; if(n ==0) printf("0.00\n") ; else{ for(i = 0 ; i< n ; i++) area += pt[i]^pt[(i + 1) %n] ; area = fabs(area) ; printf("%.2lf\n" , area * 0.5) ; } } return 0; }