算法训练 Pollution Solution
2018-03-11 15:09
155 查看
问题描述 作为水污染管理部门的一名雇员,你需要监控那些被有意无意倒入河流、湖泊和海洋的污染物。你的其中一项工作就是估计污染物对不同的水生态系统(珊瑚礁、产卵地等等)造成的影响。
你计算所使用的模型已经在图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、如果一条边的一个顶点在圆外一个顶点在圆内,则需要求出交点。
3、一条边对多边形面积的贡献用差乘来计算,对这道题来说不是整个边对多边形都有贡献。(原点为o)
1)整个边ab都在圆内:S=(向量oa x 向量ob )/2
2)顶点a在圆外,顶点b在圆内,求出与圆的交点为mid: s=(向量oa x 向量o mid )/2 +扇型面积(mid,b,r);
3)顶点b在圆外,顶点a在圆内,求出与圆的交点为mid: s=扇型面积(a,mid,r)+(向量omid x 向量o b)/2 ;
(有顺序的)
4)将所有的边的贡献都加起来就为多边形与圆相交的面积了。
原理图:
凸包面积:以p为起点,多变形的顶点为终点的有向向量,逆时针计算有向面积,作差乘即可。
源码:
你计算所使用的模型已经在图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、如果一条边的一个顶点在圆外一个顶点在圆内,则需要求出交点。
3、一条边对多边形面积的贡献用差乘来计算,对这道题来说不是整个边对多边形都有贡献。(原点为o)
1)整个边ab都在圆内:S=(向量oa x 向量ob )/2
2)顶点a在圆外,顶点b在圆内,求出与圆的交点为mid: s=(向量oa x 向量o mid )/2 +扇型面积(mid,b,r);
3)顶点b在圆外,顶点a在圆内,求出与圆的交点为mid: s=扇型面积(a,mid,r)+(向量omid x 向量o b)/2 ;
(有顺序的)
4)将所有的边的贡献都加起来就为多边形与圆相交的面积了。
原理图:
凸包面积:以p为起点,多变形的顶点为终点的有向向量,逆时针计算有向面积,作差乘即可。
源码:
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { new Main().run(); } /** * @author ZQ *向量 */ class vector{ double x,y; public vector(double x,double y) { this.x=x;this.y=y; } public double getLength(){ return Math.sqrt(x*x+y*y); } public boolean isInCircular(double r){ return ((x*x+y*y)<=r*r)?true:false; } public vector decrease(vector o){ return new vector(x-o.x,y-o.y); } /**向量的叉乘 s=1/2*axb=1/2absin(deg); * @param o * @return */ public double xmultiply(vector o){ return x*o.y-y*o.x; } public vector add(vector o){ return new vector(x+o.x,y+o.y); } } public double getSectorialA(vector a,vector b,double r){ double deg=a.xmultiply(b)/(a.getLength()*b.getLength()); if(deg<-1)deg=-1; if(deg>1)deg=1; deg=Math.asin(deg); return r*r*deg/2; } public double handle(vector a,vector b,double r){ boolean flaga=a.isInCircular(r); boolean flagb=b.isInCircular(r); double result=0; if(flaga&&flagb){//这条边全部在圆内 result=a.xmultiply(b)/2; }else if(flaga^flagb){//一端在里边 一端在外边 //找到这条线段与弧的交点 二分找 vector p=a,m=b,mid = null; for(int i=0;i<40;i++){ mid=new vector((p.x+m.x)/2, (p.y+m.y)/2); if(mid.isInCircular(r)==flaga){ p=mid; }else{ m=mid; } } if(flaga){ result=a.xmultiply(mid)/2+getSectorialA(mid, b, r); }else{ result=getSectorialA(a, mid, r)+mid.xmultiply(b)/2; } }else{//两端点都在外边 1 、线段穿过在圆内,2、线段不穿过圆内 vector p=a,m=b,mid = null,newmid=null; //找距离原点最近的点 for(int i=0;i<40;i++){ mid=new vector((p.x+m.x)/2, (p.y+m.y)/2); newmid=mid.add(new vector((m.x-p.x)*0.0001, (m.y-p.y)*0.0001)); if(mid.getLength()<newmid.getLength()){ m=mid; }else{ p=mid; } } if(mid.isInCircular(r)){//在圆内 result=handle(a, mid, r)+handle(mid, b, r); }else{ result=getSectorialA(a, b, r); } } return result; } public void run(){ Scanner sc=new Scanner(System.in); int n = sc.nextInt(); int r = sc.nextInt(); double x,y; double result=0; List<vector> vs=new ArrayList<vector>(); for(int i=1;i<=n;i++){ x=sc.nextDouble(); y=sc.nextDouble(); vector v=new vector(x, y); vs.add(v); } for(int i=0;i<n;i++){ result+=handle(vs.get(i), vs.get(((i+1)==n)?0:i+1), r); } System.out.println(result); } }
相关文章推荐
- 蓝桥杯 ALGO-11算法训练 瓷砖铺放
- 算法训练 安慰奶牛
- 算法训练 开心的金明
- 《算法竞赛-训练指南》第二章-2.26_UVa 10341
- 算法训练字串统计
- ALGO-29 算法训练 校门外的树
- 算法训练 矩阵乘法
- AdaBoost人脸检测训练算法 (下)
- 算法训练 数字三角形
- 算法-蓝桥杯-算法训练 大小写转换 (JAVA)
- 算法训练 入学考试(背包问题)
- 蓝桥杯 ALGO-100 算法训练 整除问题
- 算法-蓝桥杯-算法训练 Anagrams问题 (JAVA)
- 蓝桥杯 ALGO-142 算法训练 P1103
- 算法训练 纪念品分组
- Uva 11235 频繁出现的数值(RMQ-Sparse Table 算法)(训练指南)
- 蓝桥杯 算法训练 C++ CH08 01
- 整数算法训练04—求100以内的素数,全部打印出来
- 蓝桥网 算法训练 旅行家的预算
- 算法训练 删除数组零元素