计算几何题目总结 (只保证模板正确 代码过题)

凸包

poj  1113  Graham Scan 算法    极角排序+栈模拟

//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
inline double sqr(double x)   { return x*x;                                  }
inline int    dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
struct Point{
    double x,y;
    Point(){ x=0,y=0; }
    Point(double _x,double _y):x(_x),y(_y){}
    void input(){ scanf("%lf%lf",&x,&y); }
    Point operator -(const Point &b)const {     return Point(x-b.x,y-b.y); }
};
double dis(Point A,Point B)             {   return sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
inline double cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                               } //叉积
inline double dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                               } //点积
bool up(Point a,Point b){
    if(a.y==b.y) return a.x<b.x;
    return a.y<b.y;
}
bool cmp(Point a, Point b)//先按象限排序,再按极角排序,再按远近排序   (调精度 注意改成int或ll)
{
    if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
    if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
    if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
    if (b.y*a.y <= 0)return a.y>b.y;
    Point one;
    one.y = one.x = 0;
    return cross(one-a,one-b) > 0 || (cross(one-a,one-b) == 0 && a.x < b.x);
}
const int maxn=1e3+10;
Point pa[maxn];
int st[maxn];  //
void Graham(int n,int r){
    sort(pa,pa+n,up);
    for(int i=1;i<n;i++) { pa[i]=pa[i]-pa[0]; }  pa[0]=pa[0]-pa[0];
    sort(pa+1,pa+n,cmp);
    st[0]=0;  st[1]=1;
    int top=1;
    for(int i=2;i<n;i++){
        while(top>=1 && cross(pa[st[top]]-pa[st[top-1]],pa[i]-pa[st[top]])<=0) top--;
        st[++top]=i;
    }
    double ans=0;
    for(int i=0;i<=top;i++){
        ans+=dis(pa[st[i]],pa[st[(i+1)%(top+1)]]);
    }
    printf("%.0f
",ans+pi*r*2);
}
int main(){
    int n; scanf("%d",&n);
    int r; scanf("%d",&r);
    for(int i=0;i<n;i++) scanf("%lf %lf",&pa[i].x,&pa[i].y);
    Graham(n,r);
    return 0;
}
View Code

 poj 1113  求上下凸包  求出整个凸包    排序+上凸包+下凸包

#include <iostream>
#include <cstdio>
#include <cstring>
//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
inline double sqr(double x)   { return x*x;                                  }
inline int    dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
struct Point{
    double x,y;
    Point(){ x=0,y=0; }
    Point(double _x,double _y):x(_x),y(_y){}
    void input(){ scanf("%lf%lf",&x,&y); }
    Point operator -(const Point &b)const {     return Point(x-b.x,y-b.y); }
};
double dis(Point A,Point B)             {   return sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
inline double cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                               } //叉积
inline double dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                               } //点积
const int maxn=1e3+10;
Point pa[maxn],pt[maxn];
bool up(Point a,Point b){ if(a.x!=b.x) return a.x<b.x; return a.y<b.y;  }
int main(){
    int n,r; scanf("%d %d",&n,&r);
    for(int i=0;i<n;i++) scanf("%lf %lf",&pa[i].x,&pa[i].y);
    sort(pa,pa+n,up);
    int m=0;
    for(int i=0;i<n;i++){
        while(m>1 && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
        pt[m++]=pa[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--){
        while(m>k && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
        pt[m++]=pa[i];
    }
    if(n>1) m--;
    double ans=0;
    for(int i=1;i<m;i++) ans+=dis(pt[i],pt[i+1]); ans+=dis(pt[m],pt[1]);
    ans+=pi*r*2;  printf("%.0f
",ans);
    return 0;
}
View Code

 半平面交  

poj 3335 多边形求核  

//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const double eps=1e-8;
const double EPS=eps;
const double pi=acos(-1.0);
const double PI=pi;
inline double sqr(double x){ return x*x; }
inline int    dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
struct Point{
    double x,y;
    Point(){ x=0,y=0; }
    Point(double _x,double _y):x(_x),y(_y){}
    double operator ^(const Point &b)const{     return x*b.y-y*b.x;}//叉积
    double 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);}
};
struct Line{
    Point s,e;  // s-> 起始点  e->终点
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    Point operator &(const Line &b)const{    //求两直线交点
        Point res=s;
        double 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;
    }
};
double get_angle(Point a){   return atan2(a.y,a.x);                 }// [-PI PI]
double get_angle(Line a) {   return atan2(a.e.y-a.s.y,a.e.x-a.s.x); }
bool judge(Point *pa,int n){  // 用多边形面积来判断正负
  double ans = 0;
  for (int i=1;i<n-1; i++) { ans+=((pa[i]-pa[0])^(pa[i+1]-pa[0])); }
  return ans>=0;
}
bool cmp(Line a,Line b){ // 极角排序  同极角左边就ok了
    Point va=a.e-a.s; double x=get_angle(va);
    Point vb=b.e-b.s; double y=get_angle(vb);
    if(fabs(x-y)<eps) { return (va^(b.e-a.s))>=0;   } // 射线的左右 注意和直线区别
    else return x<y;
}
bool onright(Line a,Line b,Line c){
    /*Point o=b&c;  // 判断 o 是否在a右边
    if( ((a.e-o)^(a.s-o))>0 ) return true;
    return false;*/
    Point o = b&c;
    if (((a.e - a.s) ^ (o - a.s)) < 0) return true;
    return false;
}
const int maxn=1e2+10;
Point pa[maxn];
Line que[maxn],la[maxn];
bool HalfPlaneIntersection(Line *la,int n){
    sort(la,la+n,cmp);
    int head=0,tail=0,cnt=0;  // 栈模拟
    for (int i=0;i<n-1;i++) {
        if (fabs(get_angle(la[i])-get_angle(la[i+1]))<eps) {  // 去掉极角相同的(右边边的没用...)
          continue;
        }la[cnt++]=la[i];
    }la[cnt++]=la[n-1];
    for(int i=0;i<cnt;i++){
        //cout<<la[i].s.x<<" "<<la[i].s.y<<"->"<<la[i].e.x<<" "<<la[i].e.y<<endl;
        while(tail-head>1 && onright(la[i],que[tail-1],que[tail-2])) tail--;
        while(tail-head>1 && onright(la[i],que[head],que[head+1]))   head++;
        que[tail++]=la[i];
    }
    while(tail-head>1 && onright(que[head],que[tail-1],que[tail-2])) tail--;
    while(tail-head>1 && onright(que[tail-1],que[head],que[head+1]))   head++;
    if(tail-head<3) return false;
    return true;
}
int main(){
    int T; scanf("%d",&T);
    while(T--){
        int n; scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%lf %lf",&pa[i].x,&pa[i].y);
        }
        if(judge(pa,n)){ for(int i=0;i<n;i++)  la[i]=Line(pa[i],pa[(i+1)%n]);}
        else {           for(int i=0;i<n;i++)  la[i]=Line(pa[(i+1)%n],pa[i]);}
        //for(int i=0;i<n;i++){cout<<la[i].s.x<<" "<<la[i].s.y<<"->"<<la[i].e.x<<" "<<la[i].e.y<<endl;}
        //cout<<"---"<<endl;
        bool c=HalfPlaneIntersection(la,n);
        if(c) printf("YES
");
        else printf("NO
");
    }
}
View Code

 这个写法也OK  ONRIGHT

bool onright(Line a,Line b,Line c){
    Point o=b&c;  // 判断 o 是否在a右边
    if( ((a.e-o)^(a.s-o))>0 ) return true;
    return false;
    /*Point o = b&c;
    if (((a.e - a.s) ^ (o - a.s)) < 0) return true;
    return false;*/
}
View Code

 大佬博客 和 代码   https://blog.csdn.net/qq_40861916/article/details/83541403

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e3;
const double EPS = 1e-5;
int T, n;
typedef struct Grid {
  double x, y;
  Grid(double a = 0, double b = 0) {x = a, y = b;}
} Point, Vector;
Vector operator - (Point a, Point b) {return Vector(b.x - a.x, b.y - a.y);}
double operator ^ (Vector a, Vector b) {return a.x * b.y - a.y * b.x;}//叉乘
struct Line {
  Point s, e;// s是重点
  Line() {}
  Line(Point a, Point b) {s = a, e = b;}
};
Point p[maxn];
Line L[maxn], que[maxn];

//得到极角角度
double getAngle(Vector a) {
  return atan2(a.y, a.x);
}

//得到极角角度
double getAngle(Line a) {
  return atan2(a.e.y - a.s.y, a.e.x - a.s.x);
}

//排序:极角小的排前面,极角相同时,最左边的排在最后面,以便去重
bool cmp(Line a, Line b) {
  Vector va = a.e - a.s, vb = b.e - b.s;
  double A =  getAngle(va), B = getAngle(vb);
  if (fabs(A - B) < EPS) return ((va) ^ (b.e - a.s)) >= 0;
  return A < B;
}

//得到两直线相交的交点
Point getIntersectPoint(Line a, Line b) {
  double a1 = a.s.y - a.e.y, b1 = a.e.x - a.s.x, c1 = a.s.x * a.e.y - a.e.x * a.s.y;
  double a2 = b.s.y - b.e.y, b2 = b.e.x - b.s.x, c2 = b.s.x * b.e.y - b.e.x * b.s.y;
  return Point((c1*b2-c2*b1)/(a2*b1-a1*b2), (a2*c1-a1*c2)/(a1*b2-a2*b1));
}

//判断 b,c 的交点是否在 a 的右边
bool onRight(Line a, Line b, Line c) {
  Point o = getIntersectPoint(b, c);
  if (((a.e - a.s) ^ (o - a.s)) < 0) return true;
  return false;
}

bool HalfPlaneIntersection() {
  sort(L, L + n, cmp);//排序
  int head = 0, tail = 0, cnt = 0;//模拟双端队列
  //去重,极角相同时取最后一个。
  for (int i = 0; i < n - 1; i++) {
    if (fabs(getAngle(L[i]) - getAngle(L[i + 1])) < EPS) {
      continue;
    }
    L[cnt++] = L[i];
  }
  L[cnt++] = L[n - 1];


  for (int i = 0; i < cnt; i++) {
    //判断新加入直线产生的影响
    while(tail - head > 1 && onRight(L[i], que[tail - 1], que[tail - 2])) tail--;
    while(tail - head > 1 && onRight(L[i], que[head], que[head + 1])) head++;
    que[tail++] = L[i];
  }
  //最后判断最先加入的直线和最后的直线的影响
  while(tail - head > 1 && onRight(que[head], que[tail - 1], que[tail - 2])) tail--;
  while(tail - head > 1 && onRight(que[tail - 1], que[head], que[head + 1])) head++;
  if (tail - head < 3) return false;
  return true;
}

//判断输入点的顺序,如果面积 <0,说明输入的点为逆时针,否则为顺时针
bool judge() {
  double ans = 0;
  for (int i = 1; i < n - 1; i++) {
    ans += ((p[i] - p[0]) ^ (p[i + 1] - p[0]));
  }
  return ans < 0;
}

int main()
{
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = n - 1; i >= 0; i--) {
      scanf("%lf %lf", &p[i].x, &p[i].y);
    }

    if (judge()) {//判断输入顺序,保证逆时针连边。
      for (int i = 0; i < n; i++) {
        L[i] = Line(p[(i + 1)%n], p[i]);
      }
    } else {
      for (int i = 0; i < n; i++) {
        L[i] = Line(p[i], p[(i + 1)%n]);
      }
    }
    for(int i=0;i<n;i++){
        cout<<L[i].s.x<<" "<<L[i].s.y<<"==="<<L[i].e.x<<" "<<L[i].e.y<<endl;
    }
    if (HalfPlaneIntersection()) printf("YES
");
    else printf("NO
");
  }

  return 0;
}
View Code

 半平面交  三角形和长方形交  牛客2019国庆7

//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const double eps=1e-12;
const double EPS=eps;
const double pi=acos(-1.0);
const double PI=pi;
inline double sqr(double x){ return x*x; }
inline int    dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
struct Point{
    double x,y;
    Point(){ x=0,y=0; }
    Point(double _x,double _y):x(_x),y(_y){}
    double operator ^(const Point &b)const{     return x*b.y-y*b.x;}//叉积
    double 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);}
};
struct Line{
    Point s,e;  // s-> 起始点  e->终点
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    Point operator &(const Line &b)const{    //求两直线交点
        Point res=s;
        double 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 double cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                             } //叉积
inline double dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                             } //点积
double get_angle(Point a){   return atan2(a.y,a.x);                 }// [-PI PI]
double get_angle(Line a) {   return atan2(a.e.y-a.s.y,a.e.x-a.s.x); }
bool judge(Point *pa,int n){  // 用多边形面积来判断正负
  double ans = 0;
  for (int i=1;i<n-1; i++) { ans+=((pa[i]-pa[0])^(pa[i+1]-pa[0])); }
  return ans>=0;
}
bool cmp(Line a,Line b){ // 极角排序  同极角左边就ok了
    Point va=a.e-a.s; double x=get_angle(va);
    Point vb=b.e-b.s; double y=get_angle(vb);
    if(fabs(x-y)<eps) { return dcmp(va^(b.e-a.s))>=0;   } // 射线的左右 注意和直线区别
    else return x<y;
}
bool onright(Line a,Line b,Line c){
    /*Point o=b&c;  // 判断 o 是否在a右边
    if( ((a.e-o)^(a.s-o))>0 ) return true;
    return false;*/
    Point o = b&c;
    if (dcmp((a.e - a.s) ^ (o - a.s)) < 0) return true;
    return false;
}
const int maxn=50000+100;
Point pa[maxn];
Line que[maxn],la[maxn];
double PolygonArea(vector<Point> p){    //多边形的有向面积,加上绝对值就是面积  正值表示输入点按照逆时针 否则为顺时针
    int n=p.size(); double area=0;
    for(int i=1;i<n-1;i++)  area+=cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2; // 可改
}
double HalfPlaneIntersection(Line *la,int n){
    sort(la,la+n,cmp);
    int head=0,tail=0,cnt=0;  // 栈模拟
    for (int i=0;i<n-1;i++) {
        if (fabs(get_angle(la[i])-get_angle(la[i+1]))<eps) {  // 去掉极角相同的(右边边的没用...)
          continue;
        }la[cnt++]=la[i];
    }la[cnt++]=la[n-1];
    for(int i=0;i<cnt;i++){
        while(tail-head>1 && onright(la[i],que[tail-1],que[tail-2])) tail--;
        while(tail-head>1 && onright(la[i],que[head],que[head+1]))   head++;
        que[tail++]=la[i];
    }
    while(tail-head>1 && onright(que[head],que[tail-1],que[tail-2])) tail--;
    while(tail-head>1 && onright(que[tail-1],que[head],que[head+1]))   head++;
    if(tail-head<3) return 0.00;
   // cout<<head<<" "<<tail<<endl;
    vector<Point> vs;
    for(int i=head;i<tail-1;i++){vs.push_back(que[i]&que[i+1]);}
    vs.push_back(que[tail-1]&que[head]);
    return PolygonArea(vs);
}
int main(){
    double x1,y1,x2,y2;
    double x3,y3,x4,y4;
    while(cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4){
        int n=0;
        Point a,b,c,d; a=Point(x1,y1); b=Point(x1,y2); c=Point(x2,y1);
        vector<Point> vs;  vs.push_back(a),vs.push_back(b); vs.push_back(c);
        if(PolygonArea(vs)>=0) {
            la[n++]=Line(a,b);
            la[n++]=Line(b,c);
            la[n++]=Line(c,a);
        }
        else {
            la[n++]=Line(b,a);
            la[n++]=Line(a,c);
            la[n++]=Line(c,b);
        }
        a=Point(x3,y3); b=Point(x3,y4); c=Point(x4,y4); d=Point(x4,y3);
        vs.clear();
        vs.push_back(a); vs.push_back(b); vs.push_back(c); vs.push_back(d);
        if(PolygonArea(vs)>=0) {
            la[n++]=Line(a,b);
            la[n++]=Line(b,c);
            la[n++]=Line(c,d);
            la[n++]=Line(d,a);
        }
        else {
            la[n++]=Line(b,a);
            la[n++]=Line(a,d);
            la[n++]=Line(d,c);
            la[n++]=Line(c,b);
        }
        printf("%.10f
",HalfPlaneIntersection(la,7));
    }
}
View Code

旋转卡壳 

poj 2187   凸包直径(两点间的最远距离)   (用int  避免double的误差)

//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
struct Point{
    int x,y;
    Point(){ x=0,y=0; }
    Point(int _x,int _y):x(_x),y(_y){}
    //void output(){ printf("%.2f %.2f
",x,y); }
    int operator ^(const Point &b)const{     return x*b.y-y*b.x;}//叉积
    int 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);}
};
struct Line{
    Point s,e;
    int A,B,C;
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    void change(){A=e.y-s.y;B=s.x-e.x;C=e.x*s.y-s.x*e.y; }
};
int dis(Point A,Point B)             {   return  (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);      }
inline int cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                               } //²æ»ý
inline int dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                               } //µã»ý
bool up(Point a,Point b){ if(a.x!=b.x) return a.x<b.x; return a.y<b.y;  }
const int maxn=50000+10;
vector<Point> vs;
Point pa[maxn],pt[maxn];
void tubao(Point *pa,int n){  // 凸包求出来放在vs数组里; 有序(逆时针);
    sort(pa,pa+n,up);
    int m=0;
    for(int i=0;i<n;i++){
        while(m>1 && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
        pt[m++]=pa[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--){
        while(m>k && cross(pt[m-1]-pt[m-2],pa[i]-pt[m-2])<=0) m--;
        pt[m++]=pa[i];
    }
    if(n>1) m--;
    for(int i=1;i<=m;i++){  vs.push_back(pt[i]); }
}
int distance(Point pa,Line la){
    la.change();
    return abs(la.A*pa.x+la.B*pa.y+la.C);//  sqrt(la.A*la.A+la.B*la.B)
}
int tubao_distance(){
    if(vs.size()==0) return 0;
    if(vs.size()==1) return 0;
    if(vs.size()==2) return dis(vs[0],vs[1]);
    int p=0;
    int n=vs.size();
    int ans=0;
    for(int i=0;i<n;i++){
        Line lc=Line(vs[i],vs[(i+1)%n]);
        while(distance(vs[p],lc)<distance(vs[(p+1)%n],lc)|| distance(vs[p],lc)<distance(vs[((p-1)%n+n)%n],lc)){
            p++;  p=(p%n+n)%n;
        }
        ans=max(ans,dis(vs[i],vs[p]));
        ans=max(ans,dis(vs[(i+1)%n],vs[p]));
    }
    /*p=0;
    for(int i=0;i<n;i++){
        Line lc=Line(vs[i],vs[(i+1)%n]);
        while(dis(vs[p],vs[i])<dis(vs[(p+1)%n],vs[i])|| dis(vs[p],vs[i])<dis(vs[((p-1)%n+n)%n],vs[i])){
            p++;  p=(p%n+n)%n;
        }
        ans=max(ans,dis(vs[i],vs[p]));
        //ans=max(ans,dis(vs[(i+1)%n],vs[p]));
    }*/
    return ans;
}
int main(){
    int n; scanf("%d",&n);
    for(int i=0;i<n;i++){ scanf("%d %d",&pa[i].x,&pa[i].y);  }
    tubao(pa,n);
    int ans=tubao_distance();
    printf("%d
",ans);
}
View Code

 poj 2451 半平面交面积

//#include<bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
using namespace std;
const double eps=1e-12;
const double EPS=eps;
const double pi=acos(-1.0);
const double PI=pi;
inline double sqr(double x){ return x*x; }
inline int    dcmp(double x)  { if(fabs(x)<eps) return 0;return (x>0? 1: -1);}
struct Point{
    double x,y;
    Point(){ x=0,y=0; }
    Point(double _x,double _y):x(_x),y(_y){}
    double operator ^(const Point &b)const{     return x*b.y-y*b.x;}//叉积
    double 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);}
};
struct Line{
    Point s,e;  // s-> 起始点  e->终点
    Line(){}
    Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
    Point operator &(const Line &b)const{    //求两直线交点
        Point res=s;
        double 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 double cross(Point a,Point b)    {   return a.x*b.y-a.y*b.x;                             } //叉积
inline double dot(Point a,Point b)      {   return a.x*b.x+a.y*b.y;                             } //点积
double get_angle(Point a){   return atan2(a.y,a.x);                 }// [-PI PI]
double get_angle(Line a) {   return atan2(a.e.y-a.s.y,a.e.x-a.s.x); }
bool judge(Point *pa,int n){  // 用多边形面积来判断正负
  double ans = 0;
  for (int i=1;i<n-1; i++) { ans+=((pa[i]-pa[0])^(pa[i+1]-pa[0])); }
  return ans>=0;
}
bool cmp(Line a,Line b){ // 极角排序  同极角左边就ok了
    Point va=a.e-a.s; double x=get_angle(va);
    Point vb=b.e-b.s; double y=get_angle(vb);
    if(fabs(x-y)<eps) { return dcmp(va^(b.e-a.s))>=0;   } // 射线的左右 注意和直线区别
    else return x<y;
}
bool onright(Line a,Line b,Line c){
    /*Point o=b&c;  // 判断 o 是否在a右边
    if( ((a.e-o)^(a.s-o))>0 ) return true;
    return false;*/
    Point o = b&c;
    if (dcmp((a.e - a.s) ^ (o - a.s)) < 0) rQeturn true;
    return false;
}
const int maxn=50000+100;
Point pa[maxn];
Line que[maxn],la[maxn];
double PolygonArea(vector<Point> p){    //多边形的有向面积,加上绝对值就是面积  正值表示输入点按照逆时针 否则为顺时针
    int n=p.size(); double area=0;
    for(int i=1;i<n-1;i++)  area+=cross(p[i]-p[0],p[i+1]-p[0]);
    return fabs(area/2); // 可改
}
double HalfPlaneIntersection(Line *la,int n){
    sort(la,la+n,cmp);
    int head=0,tail=0,cnt=0;  // 栈模拟
    for (int i=0;i<n-1;i++) {
        if (fabs(get_angle(la[i])-get_angle(la[i+1]))<eps) {  // 去掉极角相同的(右边边的没用...)
          continue;
        }la[cnt++]=la[i];
    }la[cnt++]=la[n-1];
    for(int i=0;i<cnt;i++){
        while(tail-head>1 && onright(la[i],que[tail-1],que[tail-2])) tail--;
        while(tail-head>1 && onright(la[i],que[head],que[head+1]))   head++;
        que[tail++]=la[i];
    }
    while(tail-head>1 && onright(que[head],que[tail-1],que[tail-2])) tail--;
    while(tail-head>1 && onright(que[tail-1],que[head],que[head+1]))   head++;
    if(tail-head<3) return 0.00;
    vector<Point> vs;
    for(int i=head;i<tail-1;i++){vs.push_back(que[i]&que[i+1]);}
    vs.push_back(que[tail-1]&que[head]);
    return PolygonArea(vs);
}
int main(){
    int n; scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lf %lf %lf %lf",&la[i].s.x,&la[i].s.y,&la[i].e.x,&la[i].e.y);
    }
    double lim=10000;
    la[n++]=Line(Point(0,0),Point(lim,0));
    la[n++]=Line(Point(lim,0),Point(lim,lim));
    la[n++]=Line(Point(lim,lim),Point(0,lim));
    la[n++]=Line(Point(0,lim),Point(0,0));
    printf("%.1f
",HalfPlaneIntersection(la,n));
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Andromeda-Galaxy/p/11676139.html