POJ 3743 LL’s cake(圆+PSLG)
题意是给你一块在原点半径为10的圆,然后告诉你一条直线在圆弧上的极角,相当于用这条直线把这个圆分成两半,然后一共是n条直线切圆,就好比切蛋糕,问你其中最大一块的面积是多少。
如果我们将圆弧转化成直线边,那么这个题就变成PSLG裸题,但是这里是圆弧,所以我们需要将其转化。
我先将所有在圆上的点记录下来,最后极角排序,绕一周,这些点分割出来肯定会有一部分算面积的时候是要算上那部分弓型面积,但是有一部分不是,主要是这部分面积仅仅就是这块弓型面积,没有其他多边形面积,例如样例3,为了避免这种问题,我们可以直接在相邻两点之间塞入一个点,在进行连边,那么相当于我们给仅仅只有弓型区域内的点一个三角形面积,这样主要保证的是在跑PSLG的时候可以把这块面积算进去,因为每条边只算两次,但是如果是仅仅只有弓型面积所在的那条边,本来应该逆时针绕一圈算面积,所以这样就会有问题。
C++提交正确 G++wa惨???
这样就会有问题
这样建边就没有大问题了
// ——By DD_BOND //#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<functional>
#include<algorithm>
#include<iostream>
//#include<ext/rope>
#include<iomanip>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<cstdio>
#include<memory>
#include<vector>
#include<cctype>
#include<string>
#include<cmath>
#include<queue>
#include<deque>
#include<ctime>
#include<stack>
#include<map>
#include<set> #define fi first
#define se second
#define pb push_back
#define MP make_pair using namespace std; typedef double db;
typedef long long ll;
typedef pair<db,db> Pd;
typedef pair<int,int> P;
typedef pair<ll,ll> Pll; const db eps=1e-;
const int MAXN=1e5+;
const db pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f; inline int dcmp(db x){
if(fabs(x)<eps) return ;
return (x>? : -);
} inline db Sqrt(db x){
return x>? sqrt(x): ;
} inline db sqr(db x){ return x*x; } struct Point{
db x,y; int id,nx;
Point(){ x=,y=; }
Point(db _x,db _y):x(_x),y(_y){}
void input(){
double _x,_y;
scanf("%lf%lf",&_x,&_y);
x=_x,y=_y;
}
void output(){ printf("%.4f %.4f\n",(double)x,(double)y); }
bool operator ==(const Point &b)const{
return (dcmp(x-b.x)==&&dcmp(y-b.y)==);
}
bool operator !=(const Point &b)const{
return !((dcmp(x-b.x)==&&dcmp(y-b.y)==));
}
bool operator <(const Point &b)const{
return (dcmp(x-b.x)==? dcmp(y-b.y)< : x<b.x);
}
db operator ^(const Point &b)const{ //叉积
return x*b.y-y*b.x;
}
db operator *(const Point &b)const{ //点积
return x*b.x+y*b.y;
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator *(db a){
return Point(x*a,y*a);
}
Point operator /(db a){
return Point(x/a,y/a);
}
db len2(){ //长度平方
return sqr(x)+sqr(y);
}
db len(){ //长度
return Sqrt(len2());
}
db polar(){ //向量的极角
return atan2(y,x); //返回与x轴正向夹角(-pi~pi]
}
Point rotate_left(){ //逆时针旋转90度
return Point(-y,x);
}
Point rotate_right(){ //顺时针旋转90度
return Point(y,-x);
}
Point rotate(Point p,db ang){ //绕点p逆时针旋转ang度
Point v=(*this)-p;
db c=cos(ang),s=sin(ang);
return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
}
}; inline db cross(Point a,Point b){ //叉积
return a.x*b.y-a.y*b.x;
} inline db dot(Point a,Point b){ //点积
return a.x*b.x+a.y*b.y;
} inline db dis(Point a,Point b){ //两点的距离
Point p=b-a; return p.len();
} inline db rad(Point a,Point b){ //两个向量的夹角
return fabs(atan2(fabs(cross(a,b)),dot(a,b)));
} inline bool is_parallel(Point a,Point b){ //判断向量是否平行
db p=rad(a,b);
return dcmp(p)==||dcmp(p-pi)==;
} struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
Point operator &(const Line &b)const{ //求两直线交点
Point res=s;
db t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
res.x+=(e.x-s.x)*t;
res.y+=(e.y-s.y)*t;
return res;
}
}; inline int relation(Point p,Line l){ //点和向量关系 1:左侧 2:右侧 3:在线上
int c=dcmp(cross(p-l.s,l.e-l.s));
if(c<) return ;
else if(c>) return ;
else return ;
} inline bool is_parallel(Line a,Line b){ //直线平行
return is_parallel(a.e-a.s,b.e-b.s);
} struct Circle{
Point p;
db r;
Circle(){}
Circle(Point _p,db _r):p(_p),r(_r){}
}; inline int relation(Point p,Circle a){ //点和圆的位置关系 0:圆外 1:圆上 2:圆内
db d=dis(p,a.p);
if(dcmp(d-a.r)==) return ;
return (dcmp(d-a.r)<? : );
} inline db area_radian(db th,db r){ //返回半径为R,弧度为th的弓形面积
return 0.5*r*r*(th-sin(th));
} inline db polygon_area(vector<Point> p){ //多边形的有向面积,加上绝对值就是面积 正值表示输入点按照逆时针 否则为顺时针
int n=p.size(); db area=;
for(int i=;i<n-;i++) area+=cross(p[i]-p[],p[i+]-p[]);
area=fabs(area)/;
for(int i=,j=;i<n;i++,j++){
if(j==n) j=;
if(p[i].nx==p[j].id||p[j].nx==p[i].id) area+=area_radian(rad(p[i],p[j]),);
}
return area;
} struct Edge{
int from,to;
db ang;
Edge(){ ang=from=to=; }
Edge(int s,int t,db a){ from=s,to=t,ang=a; }
};
int n,m,face_cnt; //平面个数 包括外面最大的多边形
db area[MAXN]; //每个多边形面积
Point point[MAXN]; //平面内所有的点
vector<Edge>edge;
vector<int>G[MAXN];
vector<Point>polygon;
vector<Point>face[MAXN];
int vis[*MAXN],pre[*MAXN]; //left表示这条边的左侧属于哪个面
inline void Init(){
for(int i=;i<(int)edge.size();i++) vis[i]=;
edge.clear();
for(int i=;i<n;i++) G[i].clear();
for(int i=;i<face_cnt;i++) face[i].clear();
n=m=face_cnt=;
}
inline void AddEdge(int from, int to){ //需要建立反向边帮助寻找下一条边
edge.pb(Edge(from,to,(point[to]-point[from]).polar()));
edge.pb(Edge(to,from,(point[from]-point[to]).polar()));
m=edge.size();
G[from].pb(m-);
G[to].pb(m-);
}
inline void Build(){
for(int u=;u<n;u++){
int d=G[u].size();
for(int i=;i<d;i++)
for(int j=i+;j<d;j++)
if(edge[G[u][i]].ang>edge[G[u][j]].ang)
swap(G[u][i],G[u][j]);
for(int i=;i<d;i++) pre[G[u][(i+)%d]]=G[u][i]; //从u出发的i条边顺时针旋转的第一条边是pre[i]
}
for(int u=;u<n;u++){
for(int i=;i<(int)G[u].size();i++){
int e=G[u][i];
if(!vis[e]){
while(){
vis[e]=;
int from=edge[e].from;
polygon.pb(point[from]);
e=pre[e^]; //逆时针旋转最多的一条边即为顺时针转动的第一条边
if(e==G[u][i]) break;
}
face[face_cnt++]=polygon;
polygon.clear();
}
}
}
for(int i=;i<face_cnt;i++) area[i]=polygon_area(face[i]);
} typedef pair<Point,int> pdd; pdd st[MAXN];
vector<pair<db,int> >tmp[MAXN]; inline bool cmp(pdd x,pdd y){
return x.fi.polar()<y.fi.polar();
} inline void Insert(Line *line,int m){
for(int i=;i<m;i++)
for(int j=i+;j<m;j++)
if(!is_parallel(line[i],line[j])){
Point inter=line[i]&line[j];
if(dcmp(inter.len()-)>) continue;
point[n++]=inter;
}
sort(point,point+n);
n=unique(point,point+n)-point;
for(int i=;i<n;i++) point[i].id=i;
int cnt=;
for(int i=;i<n;i++)
if(dcmp(point[i].len()-)==)
st[cnt++]=pdd(point[i],i);
sort(st,st+cnt,cmp);
st[cnt]=st[];
for(int i=;i<cnt;i++) st[i].fi.nx=st[i+].fi.id;
for(int i=;i<cnt;i++) point[st[i].se]=st[i].fi;
for(int i=;i<m;i++){
for(int j=;j<n;j++)
if(relation(point[j],line[i])==)
tmp[i].pb(MP(dot(point[j]-line[i].s,line[i].e-line[i].s),j));
sort(tmp[i].begin(),tmp[i].end());
for(int j=;j<(int)tmp[i].size();j++) AddEdge(tmp[i][j-].se,tmp[i][j].se);
}
for(int i=;i<m;i++) tmp[i].clear();
Build();
} typedef pair<db,Point> pd; pd a[MAXN];
Line line[MAXN]; int main(void){
int T; scanf("%d",&T);
while(T--){
Init();
int n,m=,k=; scanf("%d",&n);
for(int i=;i<n;i++){
double x,y; scanf("%lf%lf",&x,&y);
db s=x,t=y;
Point p1=Point(*cos(s),*sin(s));
Point p2=Point(*cos(t),*sin(t));
a[k++]=pd(s,p1);
a[k++]=pd(t,p2);
line[m++]=Line(p1,p2);
}
sort(a,a+k);
k=unique(a,a+k)-a;
a[k]=a[]; a[k].fi+=*pi;
for(int i=;i<k;i++){
Point tmp;
if(dcmp(a[i+].fi-a[i].fi-pi)==) tmp=a[i].se.rotate_left();
else if(dcmp(a[i+].fi-a[i].fi-pi)>){
tmp=a[i].se+a[i+].se;
tmp=tmp/tmp.len()*-;
}
else{
tmp=a[i].se+a[i+].se;
tmp=tmp/tmp.len()*;
}
line[m++]=Line(a[i].se,tmp);
line[m++]=Line(tmp,a[i+].se);
}
Insert(line,m);
sort(area,area+face_cnt);
printf("%.2f\n",(double)area[face_cnt-]);
}
return ;
}
POJ 3743 LL’s cake(圆+PSLG)的更多相关文章
- poj 3743 LL’s cake (PSLG,Accepted)
3743 -- LL’s cake 搞了好久都过不了,看了下题解是用PSLG来做的.POJ 2164 && LA 3218 Find the Border (Geometry, PSL ...
- POJ 3675 Telescope 简单多边形和圆的面积交
这道题得控制好精度,不然会贡献WA QAQ 还是那个规则: int sgn(double x){ if(x > eps) return 1; else if(x < - eps) ret ...
- POJ 3549 GSM phone(圆+扫描线+最短路)
题目意思是求起点s到终点s的最短路,但是只能在圆的内部和边上走.一种可以想到的方法就是求出所有的交点,然后两两连边并验证合法性,但是这样的交点数规模有n2. 我们可以观察发现,我们在圆求并构成的图形中 ...
- POJ 2932 平面扫描 /// 判断圆的包含关系
题目大意: 平面上有n个两两不相交的圆,给定圆的圆心(x,y)和半径 r 求所有最外层的 即 不包含于其他圆内部的圆 挑战258页 平面扫描 记录所有圆的左端和右端 排序后 逐一扫描 将到当前圆为止的 ...
- ACM计算几何题目推荐
//第一期 计算几何题的特点与做题要领: 1.大部分不会很难,少部分题目思路很巧妙 2.做计算几何题目,模板很重要,模板必须高度可靠. 3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面 ...
- 15年-ICPC长春-网络赛
ID name status one word POJ 5437 Alisha’s Party 赛后AC. 优先队列,模拟.对时间t排序 POJ 5438 Ponds 赛后AC 循环链表 POJ 5 ...
- POJ 2932 圆扫描线
求n个圆中没有被包含的圆.模仿扫描线从左往右扫,到左边界此时如有3个交点,则有3种情况,以此判定该圆是否被离它最近的圆包含,而交点和最近的圆可以用以y高度排序的Set来维护.因此每次到左边界插入该圆, ...
- POJ 2546 & ZOJ 1597 Circular Area(求两圆相交的面积 模板)
题目链接: POJ:http://poj.org/problem? id=2546 ZOJ:problemId=597" target="_blank">http: ...
- 【POJ 1981】Circle and Points(已知圆上两点求圆心坐标)
[题目链接]:http://poj.org/problem?id=1981 [题意] 给你n个点(n<=300); 然后给你一个半径R: 让你在平面上找一个半径为R的圆; 这里R=1 使得这个圆 ...
随机推荐
- 算法复习_线性时间求解Majority Vote Algorithm问题
题目来源于Leecode上的Majority Element问题 Majority Element:在一个序列中出现了至少n/2的下界次 使用排序算法取中位数则需要Nlogn http://www.c ...
- html aside标签 语法
html aside标签 语法 aside是什么意思? aside为语义化标签,通常用来描述与文档主体内容不相关的内容,其aside标签的内容应该与附近的内容相关. 作用:定义其所处内容之外的内容.直 ...
- hdu 1695 欧拉函数+容斥原理
GCD Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- 【POJ2992】Divisors
[题目概括] 计算\(C_n^k\)的因子个数. [思路要点] 首先考虑将组合数展开,展开后就是\(\frac {n!}{k!\times (n-k)!}\). 这样就是计算出这些质因子的个数,然后将 ...
- jenkins 打标签实现回滚
背景介绍: 本项目代码存储在gitlab,再通过jenkins发布到对应的节点上. 使用tag控制版本:每一次成功的构建,jenkins会自动为gitlab的分支打上tag,版本更新可直接选择prod ...
- 根据linux自带的JDK,配置JAVA_HOME目录
在配置hadoop是,进行格式化hadoop的时候,出现找不到jdk 我用centos6.5是64位的, 发现本机有java ,就找了一下其位置 找到了jdk-1.7.0_75 which java ...
- LVM逻辑卷的扩充
LVM 的全名是 Logical Volume Manager,中文可以翻译作逻辑滚动条管理员.之所以称为”滚动条”可能是因为可以将 filesystem 像滚动条一样伸长或缩短.LVM 的作法是将几 ...
- 聊聊spring-boot-starter-data-redis的配置变更
本文主要研究一下spring-boot-starter-data-redis的配置变更 配置变更 以前是spring-boot的1.4.x版本的(spring-data-redis为1.7.x版本), ...
- 测试常用命令之awk篇
awk/gawk 1,内置变量 FILENAME:输入文件名称 FNR:当前数据文件中的数据行数 NF:数据文件中的字段总数 NR:已处理的输入数据行数目 FS:输入数据段分隔符 RS:输入数据行分隔 ...
- Java的LinkedList底层源码分析
首先我们先说一下,源码里可以看出此类不仅仅用双向链表实现了队列数据结构的功能,还提供了链表数据结构的功能.