蓝桥杯:算法训练 Pollution Solution

算法训练 Pollution Solution

问题描述

  作为水污染管理部门的一名雇员,你需要监控那些被有意无意倒入河流、湖泊和海洋的污染物。你的其中一项工作就是估计污染物对不同的水生态系统(珊瑚礁、产卵地等等)造成的影响。

image

  你计算所使用的模型已经在图1中被说明。海岸线(图1中的水平直线)为x轴,污染源位于原点(0, 0)。污染的蔓延呈半圆形,多边形代表了被波及的生态系统。你需要计算出生态系统被污染的面积,也就是图中深蓝色部分。

输入格式

  输入文件包含仅包含一组测试数据。
  每组测试数据第一行为两个整数n (3 <= n <= 100), r (1 <= r <= 1000),n表示了多边形的顶点个数,r表示了污染区域的半径;
  接下来n行,每行包含两个整数xi (-1500 <= xi <= 1500), yi (0 <= yi <=1500),表示每个顶点的坐标,以逆时针顺序给出;
  数据保证多边形不自交或触及自身,没有顶点会位于圆弧上。

输出格式

  输出多边形被圆心位于原点、半径为r的半圆覆盖的面积。
  答案的绝对误差不得超过10^-3。

样例输入

6 10
-8 2
8 2
8 14
0 14
0 6
-8 14

样例输出

101.576437872

数据规模和约定

  存在约30%的数据,n = 3,r <= 20;
  存在另外约30%的数据,n <= 10,r <= 100,坐标范围不超过100;
  存在另外约10%的数据,n <= 100,r <= 150,坐标范围不超过250;
  存在另外约30%的数据,n <= 100,r <= 1000,数据存在梯度;
  对于100%的数据,满足题目所示数据范围。

思路:

  1. 利用叉乘计算任意多边形面积的方法。
  2. 对每一对点先判断三种情况:(1)两个点都在圆内;(2)一个在圆内,一个在圆外;(3)两个点在圆外。
  3. (1)可以直接叉乘计算;(2)找到与圆的交点,分为圆内一点和交点的面积+交点和圆外点形成的扇形面积。
    (3)先判断到原点最短距离的点C是否在圆内,若不在圆内直接计算扇形面积;若在圆内,递归计算Area(A,C)+Area(C,B);

代码:

#include<iostream>
#include<math.h>
#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
#include<cctype>
#include<cstring>
#include<map>
using namespace std;
const int N=1e2+5;
const int M=N/2;

int n,r; 
int X[N],Y[N];

struct P{
    double x,y;
    double getlength(){
        return sqrt(x*x+y*y);
    }
    bool incircle(){
        return x*x+y*y<=r*r;
    }
    double cross(P &b){
        return x*b.y-y*b.x;
    }
};
double getArea(P &a,P &b){
    double degree=a.cross(b)/a.getlength()/b.getlength();
    if(degree<-1)degree=-1;
    if(degree>1)degree=1;
    degree=asin(degree);
    return r*r*degree/2;
}
double cal(P &a,P &b){
    bool in1 = a.incircle();
    bool in2 = b.incircle();
    if(in1&&in2){
        return a.cross(b)/2;
    }else if(in1!=in2){
        P l=a;
        P r=b;
        P mid;
        for(int i=0;i<40;i++){
            mid=P{(l.x+r.x)/2,(l.y+r.y)/2};
            if(mid.incircle()==in1){
                l=mid;
            }else{
                r=mid;
            }
        }
        if(in1){
            return a.cross(mid)/2+getArea(mid,b);
        }else{
            return getArea(a,mid)+mid.cross(b)/2;
        }
    }else{
        P l=a;
        P r=b;
        P mid;
        P midr;
        for(int i=0;i<40;i++){
            mid=P{(l.x+r.x)/2,(l.y+r.y)/2};
            midr=P{(l.x+r.x)/2+(r.x-l.x)*0.0001,(l.y+r.y)/2+(r.y-l.y)*0.0001};
            if(mid.getlength()<midr.getlength()){
                r=mid;
            }else{
                l=mid;
            }
        }
        if(mid.incircle()){
            return cal(a,mid)+cal(mid,b);
        }else{
            return getArea(a,b);
        }
    }
}

int main() {
    cin>>n>>r;
    for(int i=0;i<n;i++){
        cin>>X[i]>>Y[i];
    }
    X[n]=X[0];
    Y[n]=Y[0];
    double ans=0;
    for(int i=0;i<n;i++){
        P a=P{X[i],Y[i]};
        P b=P{X[i+1],Y[i+1]};
        ans+=cal(a,b);
    }
    printf("%lf\n",ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSylvie/article/details/78962444