【模板】【计几】最大四边形

题目链接: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 }
View Code

 

还有一种是用之前说到的旋转坐标系。这方法真的牛,简直开挂一样!

 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 }
View Code
posted @ 2020-01-22 20:52  小布鞋  阅读(212)  评论(0编辑  收藏  举报