标签:operator line name ble 三角形 display opera problem c++
发现计算几何算法(瞎搞)真的是博大精深。
最大三角形和最大四边形都是旋转卡壳,有模板的。这里的方法还可以求最小三角形还有最小四边形,以及三角形面积存在性问题。
求最小三角形面积(n平方):bzoj3707.
参考:http://www.pianshen.com/article/772191644/
其实就是先把n方个直线按照斜率先排了序,然后所有点按照距离y轴距离排序(距离有正负),然后枚举的直线相当于y轴,每一次旋转 “ y轴 ” 的时候维护一下这个序列。然后我们发现维护这个序列只需要交换现在直线上的两点就好了。所以n方的。然后因为我们已经枚举两个点,找第三个点使得面积最小,由于已经维护了先前的序列,所以可以O(1)找到。(由于bzoj没有权限,所以我就羞耻的引用了别人的代码当模板了哈哈哈)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const double pi=3.14159265358979; 4 const int maxn=1005; 5 const int M=1000010; 6 struct point{ 7 double x,y; 8 point(double _x=0,double _y=0){x=_x,y=_y;} 9 friend inline point operator +(const point &a,const point &b){ 10 return point(a.x+b.x,a.y+b.y); 11 } 12 friend inline point operator -(const point &a,const point &b){ 13 return point(a.x-b.x,a.y-b.y); 14 } 15 friend inline double operator *(const point &a,const point &b){ 16 return (a.x*b.y-a.y*b.x); 17 } 18 }p[maxn]; 19 struct line{ 20 int s,t; 21 double k; 22 }b[M]; 23 int n,i,j,tot=0; 24 double ans=1e18; 25 int id[maxn],pos[maxn]; 26 bool cmp(point a,point b){ 27 if(a.x==b.x) return a.y<b.y; 28 return a.x<b.x; 29 } 30 bool Cmp(line a,line b){ 31 return a.k<b.k; 32 } 33 double area(point u,line v){ 34 return fabs((p[v.s]-u)*(p[v.t]-u))*0.5; 35 } 36 int main(){ 37 scanf("%d",&n); 38 for(int i=1;i<=n;++i) 39 scanf("%lf%lf",&p[i].x,&p[i].y); 40 sort(p+1,p+n+1,cmp); 41 42 for(int i=1;i<=n;++i) id[i]=pos[i]=i; 43 for(int i=1;i<=n;++i){ 44 for(int j=i+1;j<=n;++j){ 45 ++tot; 46 b[tot].s=i,b[tot].t=j; 47 if(p[i].x==p[j].x) b[tot].k=1e18; 48 else b[tot].k=(p[i].y-p[j].y)/(p[i].x-p[j].x); 49 } 50 } 51 sort(b+1,b+tot+1,Cmp); 52 //pos[i]存的是p[i]的排名 53 //id[i]存的是 排名为i的点 54 for(int i=1;i<=tot;++i){ 55 int j=pos[b[i].s],k=pos[b[i].t]; 56 if(j>k) swap(j,k); 57 if(j>1) ans=min(ans,area(p[id[j-1]],b[i])); 58 if(k<n) ans=min(ans,area(p[id[k+1]],b[i])); 59 if(ans==0) break; 60 swap(pos[b[i].s],pos[b[i].t]); 61 swap(id[j],id[k]); 62 } 63 printf("%0.2f\n",ans); 64 }
接下来是求三角形面积存在性问题的:https://codeforces.com/problemset/problem/1019/D
其实就是刚刚的做法套个二分就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 2000+8; 5 struct Point{ 6 ll x,y; 7 bool operator < (const Point& b){ 8 if(x == b.x ) return y < b.y; 9 return x < b.x; 10 } 11 }p[N],ans1,ans2,ans3; 12 struct Line{ 13 int s,t; 14 double k; 15 bool operator < (const Line& b){ 16 return k < b.k; 17 } 18 }L[N * N]; 19 int rnk[N],id[N]; 20 int n; 21 ll S; 22 ll area(Point a,Point b,Point c){ 23 return abs( (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y) ); 24 } 25 bool binary_find(int l,int r,Point a,Point b,bool up){ 26 int res; 27 while(l<=r){ 28 int m = (l+r)>>1; 29 ll tem = area( p[ id[m] ],a,b ); 30 if( tem == 2 * S){ 31 ans1 = a;ans2 = b;ans3 = p[ id[m] ]; 32 return 1; 33 } 34 if( tem < 2 * S){ 35 if(up) l = m+1; 36 else r = m - 1; 37 } 38 else{ 39 if(up) r = m-1; 40 else l = m + 1; 41 } 42 } 43 return 0; 44 } 45 int main(){ 46 scanf("%d %lld",&n,&S); 47 for(int i = 1;i<=n;++i){ 48 scanf("%lld %lld",&p[i].x,&p[i].y); 49 } 50 sort(p+1,p+1+n); 51 for(int i = 1;i<=n;++i) id[i] = rnk[i] = i; 52 int cnt = 0; 53 for(int i = 1;i<=n;++i){ 54 for(int j = i+1;j<=n;++j){ 55 L[++cnt] = (Line){i,j}; 56 if(p[i].x == p[j].x) L[cnt].k = 1e18; 57 else L[cnt].k = 1.0 * (p[j].y - p[i].y) / (p[j].x - p[i].x); 58 } 59 } 60 sort(L+1,L+1+cnt); 61 bool ok = 0; 62 for(int i = 1;i<=cnt && (!ok) ;++i){ 63 int j = rnk[ L[i].s ] , k = rnk[ L[i].t ]; 64 if(j > k) swap(j,k); 65 if(binary_find(1,j-1,p[ L[i].s ], p[ L[i].t ] , 0)) ok = 1; 66 if(binary_find(k+1,n,p[ L[i].s ],p[ L[i].t ] , 1)) ok = 1; 67 swap( rnk[ L[i].s ] , rnk[ L[i].t ]); 68 swap(id[j],id[k]); 69 } 70 if(ok){ 71 puts("Yes"); 72 printf("%lld %lld\n%lld %lld\n%lld %lld",ans1.x,ans1.y,ans2.x,ans2.y,ans3.x,ans3.y); 73 } 74 else puts("No"); 75 return 0; 76 }
【模板】【计几】旋转坐标(用于最小三角形以及三角形四边形面积存在性问题)
标签:operator line name ble 三角形 display opera problem c++
原文地址:https://www.cnblogs.com/xiaobuxie/p/12222643.html