【模板】闵可夫斯基和以及判断点是否在凸包内

题目链接:https://www.luogu.com.cn/problem/P4557

顺带推一波学姐的博客:https://blog.csdn.net/ying971101/article/details/100110026/

1、两个点集的闵可夫斯基和 的 凸包 == 两个点集的凸包 的 闵可夫斯基 和。

2、求两个凸包的闵可夫斯基和,只需要两个凸包的顺着走的边(就是ai -> ai+1) 都拎出来,极角排序一遍,然后首尾相连即可。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 const int N = 1e5+9;
  8 typedef long long ll;
  9 struct Point{
 10     ll x,y;
 11     ll cross( Point a, Point b){
 12         return (a.x - x) * (b.y - y) - (b.x - x) * (a.y - y);
 13     }
 14     ll dot(Point a,Point b){
 15         return (a.x - x)*(b.x - x) + (a.y - y)*(b.y - y);
 16     }
 17     ll operator ^ (const Point& b)const{
 18         return x * b.y - b.x * y;
 19     }
 20     ll len()const {return x*x + y*y;}
 21     Point operator - (const Point& b)const{
 22         return (Point){ x - b.x,y - b.y};
 23     }
 24     Point operator + (const Point& b)const{
 25         return (Point){ x + b.x , y + b.y};
 26     }
 27 }pa[N],pb[N],va[N],vb[N],ch[N],pc[N],vc[N];
 28 int na,nb,nc;
 29 bool cmp1(const Point& a,const Point& b){
 30     return a.x < b.x || (a.x == b.x && a.y < b.y);
 31 }
 32 int Andrew(Point* p,int n){
 33     sort(p,p+n,cmp1);
 34     int m = 0;
 35     for(int i = 0;i<n;++i){
 36         while( m > 1 && ( ch[m-2].cross(p[i],ch[m-1]) >= 0 )) --m;
 37         ch[m++] = p[i];
 38     }
 39     int k = m;
 40     for(int i = n-2;i>=0;--i){
 41         while(m > k && ( ch[m-2].cross(p[i],ch[m-1])) >= 0) --m;
 42         ch[m++] = p[i];
 43     }
 44     if(n>1) --m;
 45     for(int i = 0;i<m;++i) p[i] = ch[i];
 46     return m;
 47 }
 48 int Minkowski(Point* pa,int na,Point* pb,int nb,Point* pc){
 49     for(int i = 0;i < na-1; ++i) va[i] = pa[i+1] - pa[i];
 50     va[na-1] = pa[0] - pa[na-1];
 51     for(int i = 0;i < nb-1; ++i) vb[i] = pb[i+1] - pb[i];
 52     vb[nb-1] = pb[0] - pb[nb-1];
 53 
 54     int cnt = 0;
 55     pc[cnt++] = pa[0] + pb[0];
 56     int p1 = 0,p2 = 0;
 57     while(p1 < na && p2 < nb){
 58         pc[cnt] = pc[cnt - 1] + ( (va[p1] ^ vb[p2]) >= 0 ? va[p1++] : vb[p2++]) ;
 59         ++cnt;
 60     }
 61     while(p1 < na){
 62         pc[cnt] = pc[cnt-1] + va[p1++];
 63         ++cnt;
 64     }
 65     while(p2 < nb){
 66         pc[cnt] = pc[cnt-1] + vb[p2++];
 67         ++cnt;
 68     }
 69     return cnt;
 70 }
 71 Point st;
 72 bool cmp2(const Point& a,const Point& b){
 73     return st.cross(a,b) > 0 || (st.cross(a,b) == 0 && (a-st).len() < (b-st).len());
 74 }
 75 bool in_cov(Point a,Point* p,int n){
 76     
 77     if( st.cross(p[1],a) < 0 || st.cross(a,p[n-1]) < 0 ) return 0;
 78     int pos = upper_bound(p,p+n,a,cmp2) - p - 1;
 79 
 80     if(p[pos].cross(a,p[(pos+1)%n]) < 0) return 1;
 81     if(p[pos].cross(a,p[(pos+1)%n]) == 0) return p[pos].dot(a,p[(pos+1)%n])>=0 ? 1 : 0;
 82     return 0;
 83 }
 84 int main(){
 85     int q;
 86     scanf("%d %d %d",&na,&nb,&q);
 87     for(int i = 0;i<na;++i) scanf("%lld %lld",&pa[i].x,&pa[i].y);
 88     for(int i = 0;i<nb;++i) scanf("%lld %lld",&pb[i].x,&pb[i].y);
 89     for(int i = 0;i<nb;++i) pb[i].x = - pb[i].x , pb[i].y = -pb[i].y;
 90     na = Andrew(pa,na);
 91     nb = Andrew(pb,nb);
 92     nc = Minkowski(pa,na,pb,nb,pc);
 93     nc = Andrew(pc,nc);
 94     Point que;
 95     st = pc[0];
 96     for(int i = 1;i<=q;++i){
 97         scanf("%lld %lld",&que.x,&que.y);
 98         printf("%d\n",in_cov(que,pc,nc)?1:0);
 99     }
100     return 0;
101 }
View Code

 

posted @ 2019-12-09 10:36  小布鞋  阅读(355)  评论(0编辑  收藏  举报