【loj6437】 【PKUSC2018】 PKUSC 计算几何
题目大意:给你一个m个点的简单多边形。对于每个点i∈[1,n],作一个以O点为原点且过点i的圆,求该圆在多边形内的圆弧长度/圆长。
其中n≤200,m≤500。
我们将n个点分开处理。
首先,我们要判断需处理的圆,是否被包含在多边形内,或者圆把多边形包含了。
我们显然可以从原点出发,向上作一条x=0的射线,判断该射线与多边形有多少个交点。
显然,若交点数量为奇数个,那么该点就在多边形内,否则在多边形外。
若圆与多边形存在交点,我们对多边形的每条边,求出其与圆,有多少个交点(0个,1个,2个,其实1个点可以当2个去处理)
这里就是简单地推个式子就可以求出,详见代码。
求出这些交点后,进行极角排序。
对于两个排序后相邻的点,我们要判断,由这两个点所构成的弧,是否被多边形包含。
有一种很暴力的思路,就是求出这两个点在弧上的中点,然后作一条从该点出发,向上作一条平行于x轴的射线,求这条射线与多边形的相交次数。
显然,若交点数量为奇数个,那么该点就在多边形内,否则在多边形外(和上面判断圆是否被包含的部分相同)。
对于每个圆,最多会出现2m个交点,最后单次判断两点所构乘的圆弧是否被多边形包含,需要O(m)的时间,则总时间复杂度为O(n*m^2)。
下面是一些需要注意的细节:
1,上述判断奇数偶数个点时,所做射线可能会经过多边形两条边的交点。考虑到输入的点全部都是整点,故对构成多边形的点集偏移2eps即可。
2,由于点要被多边形严格包含,那么在判断时,范围要向两边缩减eps。
思路简单,代码复杂,qwq....
(听说还卡精度)。。。
#include<bits/stdc++.h>
#define M 505
#define DB long double
#define eps 1e-6
#define PI 3.14159265358979323846
using namespace std; bool zero(DB x){return fabs(x)<eps;}
struct pt{
DB x,y;
pt(){x=y=;}
pt(DB xx,DB yy){x=xx; y=yy;}
friend pt operator -(pt a,pt b){return pt(a.x-b.x,a.y-b.y);}
friend bool operator <(pt a,pt b){return atan2(a.y,a.x)<atan2(b.y,b.x);}
DB mo(){return x*x+y*y;}
}; struct line{
DB a,b,c;
line(){a=b=c=;}
line(DB aa,DB bb,DB cc){a=aa; b=bb; c=cc;}
line(pt A,pt B){
DB x1=A.x,y1=A.y;
DB x2=B.x,y2=B.y;
a=y1-y2; b=x2-x1;
c=-a*x2-b*y2;
}
}; pt a[M],b[M],c[M]; int n,m;
int type[M]={};
DB sita[M]={};
DB solve(pt hh){
memset(c,,sizeof(c));
memset(type,,sizeof(type));
int cnt=,ok=;
DB R=hh.x*hh.x+hh.y*hh.y,r=sqrt(R);
for(int i=;i<=m;i++){
line p=line(b[i],b[i+]);
if(fabs(p.c/sqrt(p.a*p.a+p.b*p.b))-eps<r) ok=;
DB xl=min(b[i].x,b[i+].x),xr=max(b[i].x,b[i+].x);
DB yl=min(b[i].y,b[i+].y),yr=max(b[i].y,b[i+].y);
xl-=eps; yl-=eps; xr+=eps; yr+=eps;
DB x1,x2,y1,y2; bool is0=;
if(zero(p.a)){
y1=y2=-p.c/p.b;
DB delta=R-y1*y1;
if(delta<-eps) continue;
if(zero(delta)) is0=;
x1=-sqrt(delta); x2=sqrt(delta);
}else{
DB A=p.b*p.b+p.a*p.a;
DB B=p.b*p.c*;
DB C=p.c*p.c-R*p.a*p.a;
DB delta=B*B-*A*C;
if(delta<-eps) continue;
if(zero(delta)) is0=;
y1=(-B+sqrt(delta))/(*A);
y2=(-B-sqrt(delta))/(*A);
x1=(-p.b*y1-p.c)/p.a;
x2=(-p.b*y2-p.c)/p.a;
}
int ok1,ok2;
if(xl<=x1&&x1<=xr&&yl<=y1&&y1<=yr){ c[++cnt]=pt(x1,y1); if(is0) continue;}
if(xl<=x2&&x2<=xr&&yl<=y2&&y2<=yr) c[++cnt]=pt(x2,y2);
}
if(ok){
//return 1;
c[cnt=]=pt(,);
}else{
sort(c+,c+cnt+);
for(int i=;i<=cnt;i++) sita[i]=atan2(c[i].y,c[i].x);
}
c[cnt+]=c[]; sita[cnt+]=sita[]+*PI;
DB ans=;
for(int i=;i<=cnt;i++){
double SITA=(sita[i]+sita[i+])/;
pt hh=pt(r*cos(SITA)+eps*,r*sin(SITA));
int cnt=;
for(int j=;j<=m;j++){
double l=b[j].x,r=b[j+].x;
if(zero(b[j].x-b[j+].x)) continue;
line p=line(b[j],b[j+]);
double y=-(p.a*hh.x+p.c)/p.b;
if(l>r) swap(l,r);
l+=eps; r-=eps;
if(l<=hh.x&&hh.x<=r&&y+eps>hh.y) cnt++;
}
if(cnt&) ans+=sita[i+]-sita[i];
}
ans/=(.*PI);
return ans;
} int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) cin>>a[i].x>>a[i].y;
for(int i=;i<=m;i++) cin>>b[i].x>>b[i].y;
b[m+]=b[];
DB ans=;
for(int i=;i<=n;i++){
ans+=solve(a[i]);
//printf("%.5Lf\n",ans);
}
double res=ans;
printf("%.5lf\n",res);
}
【loj6437】 【PKUSC2018】 PKUSC 计算几何的更多相关文章
- LOJ6437 PKUSC2018 PKUSC
带劲的计算几何[这一定是我WC之前开的最后一道计几!!! 每个点画个圆然后看一下交点 然后判断是多边形内还是多边形外 这个就是取圆上中点然后射线法 eps我1e-8才过 不知道为啥有的人说只能开1e- ...
- LOJ6437. 「PKUSC2018」PKUSC [计算几何]
LOJ 思路 显然多边形旋转可以变成点旋转,不同的点的贡献可以分开计算. 然后就变成了要求一个圆在多边形内的弧长. 考虑把交点全都求出来,那么两个交点之间的状态显然是相同的,可以直接把圆弧上的中点的状 ...
- loj#6437. 「PKUSC2018」PKUSC(计算几何)
题面 传送门 题解 计算几何的东西我好像都已经忘光了-- 首先我们可以把原问题转化为另一个等价的问题:对于每一个敌人,我们以原点为圆心,画一个经过该点的圆,把这个圆在多边形内部的圆弧的度数加入答案.求 ...
- [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC
[LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC 试题描述 九条可怜是一个爱玩游戏的女孩子. 最近她在玩一个无双割草类的游戏,平面上有 \(n\) 个敌人,每一个敌人的坐标为 ...
- 【LOJ】#6437. 「PKUSC2018」PKUSC
题解 我们把这个多边形三角形剖分了,和统计多边形面积一样 每个三角形有个点是原点,把原点所对应的角度算出来,记为theta 对于一个点,相当于半径为这个点到原点的一个圆,圆弧上的弧度为theta的一部 ...
- [LOJ6437]PKUSC
旋转多边形是没有前途的,我们考虑旋转敌人,那么答案就是所有人的可行区间长度之和除以$2\pi$ 首先对每个敌人找到那些旋转后会落到多边形上的角度,实际上就是圆和一些线段求交,解方程即可,注意判一下落在 ...
- 「PKUSC2018」PKUSC
传送门 Solution 考虑求每个点的贡献 等价于一个以OA长为半径的圆心为原点的圆在多边形内的弧对应的角度/\(2\pi\) 求弧度可以利用三角剖分 在原点的点要特判,采用射线法就可以了 Cod ...
- LOJ#6437. 「PKUSC2018」PKUSC
题面 题意转化为: 判断每个点所在的圆有多长的弧度角位于多边形内部. 然后就很暴力了. 每个点P,直接找到多边形和这个圆的所有交点,按照距离P的角度排序. 找交点,直接联立二元二次方程组.... 需要 ...
- 「PKUSC2018」星际穿越 (70分做法)
5371: [Pkusc2018]星际穿越 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 27 Solved: 11[Submit][Status] ...
随机推荐
- 2018上IEC计算机高级语言(C)作业 第2次作业
2018上IEC计算机高级语言(C)作业 第2次作业 一.例程调试(20分) 调试下面1个例程,各位同学调试用自己的学号模4加1序号的题,写清错误提示(截小图)及修改内容(10分); 说明:有可能没有 ...
- 2018.09.08 NOIP模拟trip(最长链计数)
差不多是原题啊. 求最长链变成了最长链计数,其余没有变化. 这一次考试为了保险起见本蒟蒻还是写了上次没写的辅助数组. 代码: #include<bits/stdc++.h> #define ...
- Linux服务器部署系列之八—Sendmail篇
Sendmail是目前Linux系统下面用得最广的邮件系统之一,虽然它存在一些不足,不过,目前还是有不少公司在使用它.对它的学习,也能让我们更深的了解邮件系统的运作.下面我们就来看看sendmail邮 ...
- pyhthon 求GPA平均学分绩点
#coding=utf-8 ''' 北大4.0 成绩 学分 100-90 4.0 89-85 3.7 84-82 3.3 81-78 3.0 77-75 2.7 74-72 2.3 71-68 2.0 ...
- tred_extract_EDED_new
# -*- coding:utf-8 -*- import re ''' 适应新版本 ''' year='17a'#用户自定义 ss='./data/'#根目录 filename = ss+'EDED ...
- Linux 部署 tomcat 常用命令
1. 文件夹重命名 mv somedir somedir1 2. 授权所有子目录 chmod -R 777 somedir 3.授权单个目录 chmod 777 somedir 4.实时打印控制台日 ...
- Windows 下使用 GCC
MinGw 是 Minimal GNU on Windows 的缩写,允许在 GNU/Linux 和 Windows 平台生成本地的 Windows 程序而不需要第三方运行时库.本文主要介绍 MinG ...
- jmap的几个操作要慎用
JDK中带有了一堆的工具是可以用来查看运行状况,排查问题的,但对于这些工具还是要比较清楚执行后会发生什么,否则有可能会因为执行了一个命令就导致严重故障,重点讲下影响比较大的jmap. 最主要的危险操作 ...
- C++主流编译器整理(编译器版本--供应商--C++11支持情况)
C++标准 年份 C++标准 俗称 备注 2011 ISO/IEC 14882:2011 C++11 第三个C++标准 2007 ISO/IEC TR ...
- Delphi事件的广播 转
http://blog.sina.com.cn/s/blog_44fa172f0102wgs2.html 原文地址:Delphi事件的广播 转作者:MondaySoftware 明天就是五一节了,辛苦 ...