https://www.luogu.org/problemnew/show/P2283

需要注意max是求解顺序是从右到左,最好保证安全每次都清空就没问题了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; //不要输出-0.0之类的数 const double eps=1e-12;
const double inf=1e9;
const double pi=acos(-1.0); //小数点后15位精度,和atan2相同 //判断浮点数的符号
inline int cmp(double x) {
return (fabs(x)<eps)?0:((x>0.0)?1:-1);
} inline double sqr(double x) {
return x*x;
} namespace ns_Point { struct Point {
double x,y;
Point() {};
Point(const double x,const double y):x(x),y(y) {}; friend Point operator+(const Point &a,const Point &b) {
return Point(a.x+b.x,a.y+b.y);
}
friend Point operator-(const Point &a,const Point &b) {
return Point(a.x-b.x,a.y-b.y);
}
friend Point operator*(const Point &p,const double k) {
return Point(p.x*k,p.y*k);
}
friend Point operator*(const double k,const Point &p) {
return Point(p.x*k,p.y*k);
}
friend Point operator/(const Point &p,const double k) {
return Point(p.x/k,p.y/k);
}
friend bool operator==(const Point &a,const Point &b) {
return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
}
inline Point rotate(double A) {
//向量绕原点旋转A弧度
return Point(x*cos(A)-y*sin(A),x*sin(A)+y*cos(A));
}
inline double norm() {
return sqrt(sqr(x)+sqr(y));
}
inline double angle() {
//返回向量的倾斜角,[-pi, pi]
return atan2(y,x);
}
}; double det(const Point &a,const Point &b) {
return a.x*b.y-a.y*b.x;
}
double dot(const Point &a,const Point &b) {
return a.x*b.x+a.y*b.y;
}
double dist(const Point &a,const Point &b) {
return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
} } namespace ns_Line {
using namespace ns_Point; struct Line {
Point a,b;
Line() {};
Line(const Point &a,const Point &b):a(a),b(b) {};
Line move_dist(const double &d) {
//向法向平移d单位长度
//单位法向量n,从a指向b
Point n=b-a;
n=n/n.norm();
//左旋90度
n=n.rotate(pi/2.0);
return Line(a+n*d,b+n*d);
}
}; double dist_point_to_line(const Point &p,const Line &l) {
Point a=l.a,b=l.b;
//当a与b可以重合时,这里要加上下面的语句
//if(a==b)
// return a.dist(p);
if(cmp(dot(p-a,b-a))<0)
return dist(p,a);
if(cmp(dot(p-b,a-b))<0)
return dist(p,b);
return fabs(det(a-p,b-p)/dist(a,b));
}
Point point_project_on_line(const Point &p,const Line &l) {
Point a=l.a,b=l.b;
double r=dot(b-a,p-a)/dot(b-a,b-a);
return a+(b-a)*r;
}
bool point_on_line(const Point &p,const Line &l) {
Point a=l.a,b=l.b;
//这里的line是线段
//第一个cmp意思是叉积等于0,意味着直线穿过该点
//第二个cmp的<=意思是点在线段内(含端点),当改为<为点在线段内(不含端点)
return cmp(det(p-a,b-a))==0&&cmp(dot(p-a,p-b))<=0;
}
bool parallel(const Line &tl,const Line &l) {
Point a=tl.a,b=tl.b;
//叉积等于0,意味着向量平行
return !cmp(det(a-b,l.a-l.b));
}
bool intersect(const Line &tl,const Line &l,Point &p) {
Point a=tl.a,b=tl.b;
//判断直线是否相交,相交则求出交点(不需要交点可以直接return)
if(parallel(tl,l))
return false;
double s1=det(a-l.a,l.b-l.a);
double s2=det(b-l.a,l.b-l.a);
p=(b*s1-a*s2)/(s1-s2);
return true;
} } namespace ns_Polygon {
using namespace ns_Line; const int MAXN=105;
struct Polygon {
int n;
Point a[MAXN];
Polygon() {};
double perimeter() {
double sum=0.0;
a[n]=a[0];
for(int i=0; i<n; i++)
sum+=(a[i+1]-a[i]).norm();
return sum;
}
double area() {
//返回的是有向面积,画图可知顺时针点序为正向
double sum=0.0;
a[n]=a[0];
for(int i=0; i<n; i++)
sum+=det(a[i+1],a[i]);
return sum/2.0;
}
Point masscenter() {
Point ans(0.0,0.0);
//在这里,当多边形面积为0,返回的是原点
if(cmp(area())==0)
return ans;
a[n]=a[0];
for(int i=0; i<n; i++)
ans=ans+(a[i]+a[i+1])*det(a[i+1],a[i]);
return ans/area()/6.0;
}
//下面两个只有格点多边形能用
int border_point_num() {
int num=0;
a[n]=a[0];
for(int i=0; i<n; i++)
num+=__gcd(abs(int(a[i+1].x-a[i].x)),abs(int(a[i+1].y-a[i].y)));
return num;
}
int inside_point_num() {
return (int)area()+1-border_point_num()/2;
}
}; int point_in_polygon(Point &p,Polygon &po) {
Point *a=po.a;
int n=po.n;
int num=0,d1,d2,k; a[n]=a[0];
for(int i=0; i<n; i++) {
if(point_on_line(p,Line(a[i],a[i+1])))
return 2;
k=cmp(det(a[i+1]-a[i],p-a[i]));
d1=cmp(a[i].y-p.y);
d2=cmp(a[i+1].y-p.y);
if(k>0&&d1<=0&&d2>0)
num++;
if(k<0&&d2<=0&&d1>0)
num--;
}
return num!=0;
} } namespace ns_Polygon_Convex {
using namespace ns_Polygon; struct Polygon_Convex {
vector<Point> P; Polygon_Convex(int Size=0) {
P.resize(Size);
} Polygon to_polygon() {
//注意多边形的最大点数要够
Polygon p;
p.n=P.size();
for(int i=0; i<p.n; i++) {
p.a[i]=P[i];
}
return p;
} double diameter(int &First,int &Second) {
//旋转卡壳求直径,O(n)
vector<Point> &p=P;
int n=P.size();
double maxd=0.0;
if(n==1) {
First=Second=0;
return maxd;
}
for(int i=0,j=1; i<n; ++i) {
while(cmp(det(p[(i+1)%n]-p[i],p[j]-p[i])-det(p[(i+1)%n]-p[i],p[(j+1)%n]-p[i]))<0)
j=(j+1)%n;
double d=dist(p[i],p[j]);
if(d>maxd) {
maxd=d;
First=i;
Second=j;
}
d=dist(p[(i+1)%n],p[(j+1)%n]);
if(d>maxd) {
maxd=d;
First=i;
Second=j;
}
}
return maxd;
}
}; bool comp_less(const Point&a,const Point &b) {
//水平序
return (cmp(a.x-b.x)<0)||(cmp(a.x-b.x)==0&&cmp(a.y-b.y)<0);
}
Polygon_Convex convex_hull(vector<Point> a) {
Polygon_Convex res(2*a.size()+5);
sort(a.begin(),a.end(),comp_less);
a.erase(unique(a.begin(),a.end()),a.end());
int m=0,as=a.size();
for(int i=0; i<as; ++i) {
while(m>1&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2]))<=0)
--m;
res.P[m++]=a[i];
} int k=m;
for(int i=int(a.size())-2; i>=0; --i) {
while(m>k&&cmp(det(res.P[m-1]-res.P[m-2],a[i]-res.P[m-2])<=0))
--m;
res.P[m++]=a[i];
}
//当只有一个点时,凸包保留一个点,否则结尾和开头重复了
res.P.resize(m-(a.size()>1));
return res;
} int point_in_polygon_convex(const Point &p,const Polygon_Convex &pc) {
//0在外部,1在内部,2在边界上
//包括边界
int n=pc.P.size();
const vector<Point> &P=pc.P;
//找一个内部点
Point g=(P[0]+P[n/3]+P[2*n/3])/3.0;
int l=0,r=n;
while(l+1<r) {
int mid=(l+r)>>1;
if(cmp(det(P[l]-g,P[mid]-g))>0) {
if(cmp(det(P[l]-g,p-g))>=0&&cmp(det(P[mid]-g,p-g))<0)
r=mid;
else
l=mid;
} else {
if(cmp(det(P[l]-g,p-g))<0&&cmp(det(P[mid]-g,p-g))>=0)
l=mid;
else
r=mid;
}
}
r%=n;
int z=cmp(det(P[r]-p,P[l]-p));
//z==0在边界上,三点共线
//z==1在凸包外
//z==-1在凸包内
return (z+2)%3;
} } namespace ns_Halfplane {
using namespace ns_Point; struct Halfplane {
//向量first->second的左侧
Point first,second;
Halfplane() {};
Halfplane(Point p1,Point p2):first(p1),second(p2) {};
}; inline int satisfy(Point a,Halfplane p) {
return cmp(det(a-p.first,p.second-p.first))<=0;
} Point intersect_point(const Halfplane &a,const Halfplane &b) {
double k=det(b.first-b.second,a.first-b.second);
double t=det(b.first-b.second,a.second-b.second);
//反向向量已经被半平面交制裁了,这个函数调用之前就要先保证不平行,否则后果自负
//把边界也放进来了,所以反向向量至少转180度会遇到边界
k=k/(k-t);
return a.first+(a.second-a.first)*k;
} inline bool compare(const Halfplane &a,const Halfplane &b) {
int res=cmp((a.second-a.first).angle()-(b.second-b.first).angle());
return res==0?satisfy(a.first,b):res<0;
} inline bool parallel(const Halfplane &a,const Halfplane &b){
Point pa=a.second-a.first;
Point pb=b.second-b.first;
return !cmp(det(pa,pb));
} //半平面交,O(nlogn)
vector<Point> halfplane_intersection(vector<Halfplane> v) {
//半平面把边界放进来,不可能是空的
if(v.empty())
return vector<Point>();
sort(v.begin(),v.end(),compare);
deque<Halfplane> q;
deque<Point> ans;
q.push_back(v[0]); int vs=v.size();
for(int i=1; i<vs; ++i) {
if(cmp((v[i].second-v[i].first).angle()-(v[i-1].second-v[i-1].first).angle())==0)
continue;
while(!ans.empty()&&!satisfy(ans.back(),v[i])) {
ans.pop_back();
q.pop_back();
}
while(!ans.empty()&&!satisfy(ans.front(),v[i])) {
ans.pop_front();
q.pop_front();
}
//前面已经去掉平行了,再平行就是反平行
if(parallel(q.back(),v[i]))
return vector<Point>();
ans.push_back(intersect_point(q.back(),v[i]));
q.push_back(v[i]);
}
while(!ans.empty()&&!satisfy(ans.back(),q.front())) {
ans.pop_back();
q.pop_back();
}
while(!ans.empty()&&!satisfy(ans.front(),q.back())) {
ans.pop_front();
q.pop_front();
}
ans.push_back(intersect_point(q.back(),q.front()));
if(ans.size()<3){
//三线共点
return vector<Point>();
}
return vector<Point>(ans.begin(),ans.end());
} } using namespace ns_Polygon;
using namespace ns_Halfplane; vector<Point> Po;
vector<Halfplane> Hp; int n; double solve2(){
Hp.clear();
for(int j=0; j<n; j++)
Hp.push_back(Halfplane(Po[j],Po[(j+1)%n])); Hp.push_back(Halfplane(Point(-inf,-inf),Point(inf,-inf)));
Hp.push_back(Halfplane(Point(inf,-inf),Point(inf,inf)));
Hp.push_back(Halfplane(Point(inf,inf),Point(-inf,inf)));
Hp.push_back(Halfplane(Point(-inf,inf),Point(-inf,-inf))); vector<Point> ans=halfplane_intersection(Hp); int as=ans.size();
if(as<3)
return 0.0; double sum=0.0;
for(int i=0; i<as; i++)
sum+=det(ans[(i+1)%as],ans[i]);
sum/=2.0; return fabs(sum);
} double solve3(){
Hp.clear();
for(int j=0; j<n; j++)
Hp.push_back(Halfplane(Po[(j+1)%n],Po[j])); Hp.push_back(Halfplane(Point(-inf,-inf),Point(inf,-inf)));
Hp.push_back(Halfplane(Point(inf,-inf),Point(inf,inf)));
Hp.push_back(Halfplane(Point(inf,inf),Point(-inf,inf)));
Hp.push_back(Halfplane(Point(-inf,inf),Point(-inf,-inf))); vector<Point> ans=halfplane_intersection(Hp); int as=ans.size();
if(as<3)
return 0.0; double sum=0.0;
for(int i=0; i<as; i++)
sum+=det(ans[(i+1)%as],ans[i]);
sum/=2.0; return fabs(sum);
} void solve() {
scanf("%d",&n);
for(int j=1; j<=n; j++) {
double x,y;
scanf("%lf%lf",&x,&y);
Po.push_back(Point(x,y));
}
double ans=max(solve2(),solve3());
printf("%.2f\n",ans);
} int main() {
#ifdef Yinku
freopen("Yinku.in","r",stdin);
#endif // Yinku
solve();
return 0;
}

洛谷 - P2283 - 多边形 - 半平面交的更多相关文章

  1. 洛谷 - P1663 - 山 - 半平面交

    https://www.luogu.org/problemnew/show/P1663 给定山的性状,求一个最低点可以看见所有的地方. 就是半平面交. 粘贴全家福: #include<bits/ ...

  2. 洛谷P3222 [HNOI2012]射箭(计算几何,半平面交,双端队列)

    洛谷题目传送门 设抛物线方程为\(y=ax^2+bx(a<0,b>0)\),我们想要求出一组\(a,b\)使得它尽可能满足更多的要求.这个显然可以二分答案. 如何check当前的\(mid ...

  3. poj3335 半平面交

    题意:给出一多边形.判断多边形是否存在一点,使得多边形边界上的所有点都能看见该点. sol:在纸上随手画画就可以找出规律:按逆时针顺序连接所有点.然后找出这些line的半平面交. 题中给出的点已经按顺 ...

  4. POJ 3130 How I Mathematician Wonder What You Are! /POJ 3335 Rotating Scoreboard 初涉半平面交

    题意:逆时针给出N个点,求这个多边形是否有核. 思路:半平面交求多边形是否有核.模板题. 定义: 多边形核:多边形的核可以只是一个点,一条直线,但大多数情况下是一个区域(如果是一个区域则必为 ).核内 ...

  5. bzoj2618[Cqoi2006]凸多边形 半平面交

    这是一道半平面交的裸题,第一次写半平面交,就说一说我对半平面交的理解吧. 所谓半平面交,就是求一大堆二元一次不等式的交集,而每个二元一次不等式的解集都可以看成是在一条直线的上方或下方,联系直线的标准方 ...

  6. BZOJ2618[Cqoi2006]凸多边形——半平面交

    题目描述 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. 输入 第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形.第 ...

  7. 【kuangbin专题】计算几何_半平面交

    1.poj3335 Rotating Scoreboard 传送:http://poj.org/problem?id=3335 题意:就是有个球场,球场的形状是个凸多边形,然后观众是坐在多边形的边上的 ...

  8. BZOJ 4445 [Scoi2015]小凸想跑步:半平面交

    传送门 题意 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸 $ n $ 边形,$ n $ 个顶点 $ P_i $ 按照逆时针从 $ 0 $ 至 $ n-1 $ 编号. ...

  9. 【bzoj2618】[Cqoi2006]凸多边形 半平面交

    题目描述 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. 输入 第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形.第 ...

随机推荐

  1. linux 块设备驱动 (三)块设备驱动开发

    一: 块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为:int register_blkdev(unsigne ...

  2. php跳转

    header("Location: http://bbs. lampbrother.net"); header("refresh:0;url=./login.php&qu ...

  3. MongoDB连接数与连接优化

    默认每个连接数占用10M内存 ulimit -a 查看stack size MongoDB服务器内存要满足 connection overhead + data size + index size 即 ...

  4. 【TensorFlow-windows】(四) CNN(卷积神经网络)进行手写数字识别(mnist)

    主要内容: 1.基于CNN的mnist手写数字识别(详细代码注释) 2.该实现中的函数总结 平台: 1.windows 10 64位 2.Anaconda3-4.2.0-Windows-x86_64. ...

  5. iOS开发中的单元测试(三)——URLManager中的测试用例解析

    本文转载至 http://www.cocoachina.com/cms/plus/view.php?aid=8088   此前,我们在<iOS开发中的单元测试(一)&(二)>中介绍 ...

  6. IOS下SQLite的简单使用

    本文转载至 http://www.cnblogs.com/cokecoffe/archive/2012/05/31/2537105.html 看着国外网站的教程,写了一个小例子,一个联系人的程序,包括 ...

  7. mysql学习之基础知识

    一.什么是数据库 一般而言,数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.我们也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢.所以,使用关系型数据库管理系统(RDB ...

  8. 【C++基础学习】引用和指针、重载、函数、内存管理

    第一部分:引用VS指针 引用的含义:变量的别名 注意:变量不能只有别名,必须有一个真实的变量与之相对应 基本数据类型的引用 对别名本身的操作和它的实体的操作是一样的 1.基本数据类型的引用 类型 &a ...

  9. SOAP Only Authentication Using C#

                Jason Lattimer's Blog                 Monday, February 9, 2015 SOAP Only Authentication ...

  10. 在iOS平台使用ffmpeg解码h264视频流(转)

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...