【模板】【计几】最大四边形
题目链接:https://codeforces.com/group/uVAsoW2Jkj/contest/265761
L题。
类似于旋转卡壳:
1 #include<iostream> 2 #include<cassert> 3 #include<bits/stdc++.h> 4 using namespace std; 5 typedef long long ll; 6 const int N = 4100; 7 #define eps 1e-10 8 struct Point{ 9 ll x,y,id; 10 bool operator < (const Point& b)const{ 11 return x < b.x || (x==b.x && y < b.y); 12 } 13 Point operator - (const Point& b)const{ 14 return (Point){ x - b.x,y - b.y}; 15 } 16 ll operator ^ (const Point b)const{ 17 return x * b.y - b.x * y; 18 } 19 }p[N],ch[N],p0; 20 ll cross(Point o,Point a,Point b){ 21 return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); 22 } 23 ll area(Point o,Point a,Point b){ 24 ll tem = cross(o,a,b); 25 if(tem < 0) tem = -tem; 26 return tem; 27 } 28 int n,m; 29 int Andrew(){ 30 sort(p,p+n); 31 m = 0; 32 for(int i = 0;i<n;++i){ 33 while( m > 1 && ( (p[i] - ch[m-2]) ^ (ch[m-1] - ch[m-2]) ) >= 0 ) --m; 34 ch[m++] = p[i]; 35 } 36 int k = m; 37 for(int i = n-2;i>=0;--i){ 38 while( m > k && ( (p[i] - ch[m-2]) ^ ( ch[m-1] - ch[m-2])) >= 0 ) --m; 39 ch[m++] = p[i]; 40 } 41 if(n>1) --m; 42 return m; 43 } 44 int main(){ 45 int T; scanf("%d",&T); 46 while(T--){ 47 scanf("%d",&n); 48 for(int i = 0;i<n;++i) scanf("%lld %lld",&p[i].x,&p[i].y),p[i].id = i; 49 Andrew(); 50 ll ans = 0; 51 if(m==3){ 52 ll all = area(ch[0],ch[1],ch[2]); 53 ll tem = 1000000000000000000; 54 for(int i = 0;i<n;++i){ 55 if(p[i].id == ch[0].id || p[i].id == ch[1].id || p[i].id == ch[2].id) continue; 56 tem = min( tem,min( min(area(p[i],ch[0],ch[1]),area(p[i],ch[0],ch[2])), area(p[i],ch[1],ch[2]) )); 57 } 58 ans = all - tem; 59 }else if(m > 3){ 60 for(int k = 0;k<m;++k){ 61 int l = 1,r = 3; 62 for(int i = 2;i<m-1;++i){ 63 while( l+1 < i && area(ch[0],ch[l+1],ch[i]) >= area(ch[0],ch[l],ch[i])) ++l; 64 while( r+1 < m && area(ch[0],ch[r+1],ch[i]) >= area(ch[0],ch[r],ch[i])) ++r; 65 ans = max(ans,area(ch[0],ch[i],ch[r]) + area(ch[0],ch[i],ch[l])); 66 //if(ch[0].x == 1 && ch[0].y == 2) cerr<<"l r"<<l<<" "<<r<<" "<<" "<<i<<"i"<<area(ch[0],ch[i],ch[r]) <<" "<< area(ch[0],ch[i],ch[l])<<endl; 67 } 68 //cerr<<ch[0].x<<" "<<ch[0].y<<" "<<ans<<endl; 69 //if(ch[0].x == 1 && ch[0].y == 2) for(int i = 0;i<m;++i) cerr<<ch[i].x<<" "<<ch[i].y<<"a"<<endl; 70 ch[m] = ch[0]; 71 for(int i = 0;i<m;++i) ch[i] = ch[i+1]; 72 } 73 } 74 if(ans&1) printf("%lld.5\n",ans/2); 75 else printf("%lld\n",ans/2); 76 } 77 return 0; 78 }
还有一种是用之前说到的旋转坐标系。这方法真的牛,简直开挂一样!
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 5000; 5 struct Point{ 6 ll x,y; 7 bool operator < (const Point& b)const{ 8 if( x== b.x) return y < b.y; 9 return x < b.x; 10 } 11 }p[N]; 12 struct Line{ 13 int s,t; 14 double k; 15 bool operator < (const Line& b)const{ 16 return k < b.k; 17 } 18 }L[N*N]; 19 int id[N],rnk[N]; 20 ll cross(Point a,Point b,Point c){ 21 return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); 22 } 23 int main(){ 24 int T; scanf("%d",&T); 25 while(T--){ 26 int n; scanf("%d",&n); 27 for(int i = 1;i<=n;++i) scanf("%lld %lld",&p[i].x,&p[i].y); 28 sort(p+1,p+1+n); 29 for(int i = 1;i<=n;++i) id[i] = rnk[i] = i; 30 int cnt = 0; 31 for(int i = 1;i<=n;++i){ 32 for(int j = i+1;j<=n;++j){ 33 L[++cnt] = (Line){ i,j,atan2(p[j].y - p[i].y,p[j].x - p[i].x)}; 34 } 35 } 36 sort(L+1,L+1+cnt); 37 ll ans = 0; 38 for(int i = 1;i<=cnt;++i){ 39 int l,r,k = 1; 40 int s = L[i].s , t = L[i].t; 41 while(id[k] == s || id[k] == t) ++k; 42 l = k; 43 k = n; 44 while(id[k] == s || id[k] == t) --k; 45 r = k; 46 ll crol = cross(p[s],p[t],p[ id[l] ]) , cror = cross(p[s],p[t],p[ id[r] ]); 47 ans = max(ans,abs( crol - cror)); 48 l = rnk[ L[i].s ] ; r = rnk[ L[i].t ]; 49 swap( id[l] , id[r] ); 50 swap( rnk[L[i].s] , rnk[L[i].t]); 51 //cerr<<L[i].s<<" "<<L[i].t<<" "<<ans<<" "<<crol<<" "<<cror<<endl; 52 } 53 if(ans&1) printf("%lld.5\n",ans/2); 54 else printf("%lld\n",ans/2); 55 } 56 return 0; 57 }