Minkowski sum
BZOJ2564
将两个凸包的边按极角顺序合并即可
#include <cstdio> #include <cmath> #include <algorithm> #define LDB long double #define LL long long using namespace std; const LDB eps=1e-6; int totcnt=0,n,m; struct data{ LDB x,y,alp; }a[500011],tmp[500011],sta[500011],ans[500011]; inline data operator - (const data&a,const data&b) {return (data){a.x-b.x,a.y-b.y,a.alp};} LL X(data a,data b){ return((LL)a.x*(LL)b.y-(LL)a.y*(LL)b.x); } LDB dis(data a,data b){ return(sqrt((long double)((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)))); } int mycomp(const data&aa,const data&b){ if (X(aa-a[1],b-a[1])>0) return(1); if (X(aa-a[1],b-a[1])<0) return(0); return(dis(a[1],aa)>dis(a[1],b)); } int mycomp2(const data&a,const data&b){ return(a.alp<b.alp); } void graham(int n){ int xmini=1e9,ymini=1e9; int po; for (int i=1;i<=n;i++){ if (ymini>tmp[i].y||(ymini==tmp[i].y&&tmp[i].x<xmini)){ xmini=tmp[i].x;ymini=tmp[i].y; po=i; } } data t=tmp[po];tmp[po]=tmp[1];tmp[1]=t; a[1].x=xmini;a[1].y=ymini; sort(tmp+2,tmp+n+1,mycomp); int cnt=1; tmp[1].x=-1e9;tmp[1].y=-1e9; for (int i=2;i<=n;i++) if (X(tmp[i]-tmp[1],tmp[i-1]-tmp[1])!=0||i==2) a[++cnt]=tmp[i]; n=cnt; int top=0; for (int i=1;i<=n;i++){ while (top>=2&&X(sta[top]-sta[top-1],a[i]-sta[top-1])<-eps) top--; sta[++top]=a[i]; } for (int i=2;i<=top;i++) ans[++totcnt]=sta[i]-sta[i-1]; ans[++totcnt]=sta[1]-sta[top]; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%Lf%Lf",&tmp[i].x,&tmp[i].y); graham(n); for (int i=1;i<=m;i++) scanf("%Lf%Lf",&tmp[i].x,&tmp[i].y); graham(m); for (int i=1;i<=totcnt;i++) ans[i].alp=atan2(ans[i].y,ans[i].x); sort(ans+1,ans+totcnt+1,mycomp2); LL fin=0; data o;o.x=o.y=0; for (int i=1;i<=totcnt;i++){ data t;t.x=o.x+ans[i].x;t.y=o.y+ans[i].y; fin+=X(o,t); o=t; } printf("%lld\n",(LL)fin); }