计算几何模板
来源:互联网 发布:c语言中的echo 编辑:程序博客网 时间:2024/06/05 15:45
求锐角三角形个数.
统计锐角的个数,设为
每个锐角三角形有三个锐角,每个钝角和直角三角形均贡献两个锐角
所以答案即为
然后题解在对每个点极角排序之后,采用 two pointers的方式来找上下界
比二分好写多了,也很方便,时间复杂度
#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 2e3+10;int n;struct Point{ ll x,y; Point(ll xx=0,ll yy=0) { x=xx; y=yy; } Point operator -(const Point & a) const { return Point(x-a.x,y-a.y); }}p[maxn];ll xmul(const Point &a,const Point &b){ return a.x*b.y - a.y*b.x;}ll dot(const Point &a,const Point &b){ return a.x*b.x+a.y*b.y;}bool cmp(const Point &a,const Point &b){ if(a.y * b.y <=0) { if(a.y >0 || b.y > 0) return a.y < b.y; if(a.y == 0 && b.y ==0) return a.x < b.x; } return xmul(a,b) > 0;}vector<Point>vec;int main(){ while(~scanf("%d",&n)) { ll zhidun = 0,rui = 0,ans = 0; for(int i = 0;i < n;i++) scanf("%lld %lld",&p[i].x,&p[i].y); for(int cor = 0;cor < n;cor++) { vec.clear(); for(int i = 0;i < n ;i++) { if(i != cor) { vec.emplace_back(p[i]-p[cor]); } } sort(vec.begin(),vec.end(),cmp); vec.insert(vec.end(),vec.begin(),vec.end()); int j=0,k=0,r=0; for(int i=0;i<n-1;i++) { while(j<i+n-1&&xmul(vec[i],vec[j])==0&&dot(vec[i],vec[j])>0) j++; k=max(k,j); while(k<i+n-1&&xmul(vec[i],vec[k])>0&&dot(vec[i],vec[k])>0) k++; r=max(r,k); while(r<i+n-1&&xmul(vec[i],vec[r])>0) r++; rui += k-j; zhidun+=r-k; } } ans = (rui-2*zhidun)/3; printf("%lld\n",ans); } return 0;}
射线法判断点和多边形位置关系
/*射线法:判断一个点是在多边形内部,边上还是在外部,时间复杂度为O(n);射线法可以正确用于凹多边形;射线法是使用最广泛的算法,这是由于相比较其他算法而言,它不但可以正确使用在凹多边形上,而且不需要考虑精度误差问题。该算法思想是从点出发向右水平做一条射线,计算该射线与多边形的边的相交点个数,当点不在多边形边上时,如果是奇数,那么点就一定在多边形内部,否则,在外部。需要注意的是: 射线法判断点和多边形位置关系,多边形的点要求必须是逆时针描述. */#include <stdio.h>#include <algorithm>#include <cstring>#include <cmath>using namespace std;const int N = 2010;const double eps = 1e-10;const int INF = 0x3f3f3f3f;struct point{ double x, y; point(double x=0, double y=0) : x(x), y(y){} friend point operator - (const point& p1, const point& p2) { return point(p1.x-p2.x, p1.y-p2.y); } friend double operator ^ (const point& p1, const point& p2) { return p1.x*p2.y - p1.y*p2.x; }};struct Segment{ point s, e;};///判断一个double类型的数是 0 <0 >0;int Sign(double x){ if( fabs(x) < eps )return 0; if(x > 0)return 1; return -1;}///判断o在ab的哪边;0:o在直线ab上; >0:在左边; <0:在右边;double cross(point o, point a, point b){ return ((a-o)^(b-o));}///已知abc三点在一条直线上,判断点a是否在线段bc之间;<=0:在 >0:不在;int Between(point a, point b, point c){ if(fabs(b.x-c.x) > fabs(b.y-c.y)) return Sign(min(b.x, c.x)-a.x)*Sign(max(b.x, c.x)-a.x); else return Sign(min(b.y, c.y)-a.y)*Sign(max(b.y, c.y)-a.y);}///判断点p0和线段S上,<=0:在,1:不在;int PointOnSegment(point p0, Segment S){ if(Sign(cross(S.s, S.e, p0)) == 0) return Between(p0, S.s, S.e); return 1;}///求线段a和线段b的交点个数;int SegmentCross(Segment a, Segment b){ double x1 = cross(a.s, a.e, b.s); double x2 = cross(a.s, a.e, b.e); double x3 = cross(b.s, b.e, a.s); double x4 = cross(b.s, b.e, a.e); if(Sign(x1*x2)<0 && Sign(x3*x4)<0) return 1; if((Sign(x1)==0 && Between(b.s, a.s, a.e)<=0) || (Sign(x2)==0 && Between(b.e, a.s, a.e)<=0) || (Sign(x3)==0 && Between(a.s, b.s, b.e)<=0) || (Sign(x4)==0 && Between(a.e, b.s, b.e)<=0)) return 2; return 0;}///判断点p0与含有n个节点的多边形的位置关系//p数组是顶点集合; 射线法判断点和多边形位置关系,多边形的点要求必须是逆时针描述. ///返回0:边上或顶点上, 1:外面, -1:里面;int PointInPolygon(point p0, point p[], int n){ Segment L, S; point temp; L.s = p0, L.e = point(INF, p0.y);///以p0为起点的射线L; int counts = 0; p[n] = p[0]; for(int i=1; i<=n; i++) { S.s = p[i-1], S.e = p[i]; if(PointOnSegment(p0, S) <= 0) return 0; if(S.s.y == S.e.y) continue;///和射线平行; if(S.s.y > S.e.y) temp = S.s; else temp = S.e; if(PointOnSegment(temp, L) == -1) counts ++; else if(SegmentCross(L, S) == 1) counts ++; } if(counts%2) return -1; return 1;}int main(){ point p[N]; int T, tCase = 1, n, q; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=0; i<n; i++) scanf("%lf %lf", &p[i].x, &p[i].y); scanf("%d", &q); printf("Case %d:\n", tCase++); for(int i=1; i<=q; i++) { int x, y; scanf("%d %d", &x, &y); int ans = PointInPolygon(point(x, y), p, n); if(ans == 1) puts("No"); else puts("Yes"); } } return 0;}
凸包
/*采用Graham扫描算法,复杂度nlogn.栈中保存点的顺序是按照逆时针顺序 */#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <vector>using namespace std;const int MAXN = 50000 + 5;struct P{ int x, y; };P p[MAXN];int n;//求两点之间的距离 int dis(P a, P b){ return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);}/*计算叉积判断点和直线的方向用叉积若P1×p2 >0 则p1在p2的顺时针方向.<0 p1在p2的逆时针方向= 0 共线 */ int cross(P a, P b, P c){ return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);}//极角排序 bool cmp(P a, P b){ int x = cross(p[0],a,b); if(x > 0 || (x == 0 && dis(a, p[0]) < dis(b, p[0]))) return 1; return 0;}vector<P> Graham(){ vector<P> stk(n);//存凸包 int k = 0; //Graham 算法 for (int i = 0; i < n; i++) { while (k > 1 && (cross(p[i], stk[k-2], stk[k-1])) <= 0) k--; stk[k++] = p[i]; } stk.resize(k);//调整正确的凸包顶点数 return stk;}int main(){ while (~scanf("%d", &n)) { int ans = 0, rp = 0;//rp用于临时保存最左下点的下标 //输入 for (int i = 0; i < n; i++) { scanf("%d%d", &p[i].x, &p[i].y); if(p[rp].y > p[i].y || (p[rp].y == p[i].y && p[rp].x > p[i].x))//找最左下的点 rp = i; } //极角排序 swap(p[rp], p[0]);//初始化,方便cmp过程 sort(p + 1, p + n, cmp); //Graham Scan构成凸包 vector<P> stk = Graham(); //暴力求解 for (int i = 0; i < stk.size(); i++) { for (int j = 0; j < i; j++) ans = max(ans, dis(stk[i], stk[j])); } cout<<ans<<endl; } return 0;}#include<iostream>#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=5e4+5;struct node{int x,y;}a[maxn],sta[maxn];//求亮点之间距离的平方. int dis(node n1,node n2){return (n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y);}//计算叉积 int det(int x1,int y1,int x2,int y2) { return x1*y2-x2*y1; } //判断点和直线的方向用叉积//若P1×p2 >0 则p1在p2的顺时针方向.//<0 p1在p2的逆时针方向//= 0 共线 int cross(node a,node n1,node n2){return det(n1.x-a.x,n1.y-a.y,n2.x-a.x,n2.y-a.y); }//极角排序 bool cmp(node n1,node n2){//a[0]为纵坐标最小的点一定在凸包上,以它为原点进行极角排序 int k = cross(a[0],n1,n2);if(k > 0) return 1;//角度小的排在前面 //若共线则距离a[0]距离近的在前面. if(k == 0 && dis(a[0],n1) < dis(a[0],n2))return 1;return 0;} void solve(node *ch,int len){int ans = 0;for(int i = 0;i <= len;++i){for(int j = i + 1;j <= len;++j){ans = max(ans,dis(ch[i],ch[j]));}}cout<<ans<<endl;}//最后栈中存的点就是凸包上的点. void Graham(int n){int i,head;for(i = 1;i < n;++i) //先找到最下面的那个点作为原点. if(a[i].x < a[0].x || (a[i].x == a[0].x && a[i].y < a[0].y))swap(a[0],a[i]); sort(a+1,a+n,cmp);//极角排序 a[n] = a[0];sta[0] = a[0];//最下面的一个点和第二个点一定在凸包上. sta[1] = a[1];sta[2] = a[2];head = 2;//Graham 算法 for(int i = 3;i < n;++i){while(head >= 2){int fu = cross(sta[head - 1],sta[head],a[i]);if(fu < 0) head--;else if(fu == 0 && dis(sta[head - 1],a[i]) > dis(sta[head - 1],sta[head])) head--;elsebreak;}sta[++head] = a[i];}solve(sta,head);}int main(){int n;while(scanf("%d",&n) > 0){for(int i = 0;i < n;++i){scanf("%d %d",&a[i].x,&a[i].y);}Graham(n);}return 0;}
叉积求多边形面积
/*叉积求多边形面积.(凹凸都适用)要求所有顶点按照逆时针顺序排列(点和多边形、凸包都是逆时针)由于叉积可能为负所以要取绝对值。因为每次除有误差,记得全部求完面积在除以2. */ double get_area(node *p,int len){double ans = 0;for(int i = 1;i < len;++i){ans += fabs(cross(p[0],p[i],p[i+1]));}return ans*0.5;}
阅读全文
0 0
- [模板]计算几何模板
- 经典计算几何模板
- 计算几何模板2
- 计算几何 模板
- 计算几何模板
- 计算几何经典模板
- 计算几何模板
- ACM计算几何模板
- 计算几何模板
- 计算几何模板
- 计算几何模板
- 计算几何 模板
- 计算几何初步模板
- 计算几何三维模板
- 二维计算几何模板
- 计算几何模板
- 计算几何模板
- 计算几何的模板
- R生成latex表格代码
- Linux/Unix系统编程-基本概念
- TFIDF算法Java实现
- Oracle优化——LIKE与索引(以%开头的LIKE会不走索引或走索引全扫描)
- Java类的生命周期
- 计算几何模板
- 简单理解:一维单高斯 多维单高斯 混合多高斯GMM
- Android开发艺术探索读书笔记-View的事件体系(一)
- 前端
- 第一题 two-sum
- 移动端选择日期
- FIleInputStream中read和Socket中read源码分析
- Java堆、栈和常量池以及相关String的详细讲解(经典中的经典)
- 138. Copy List with Random Pointer