HDU 6538 Neko and quadrilateral(極角排序+旋轉坐標系)


這道題簡直太好了,對於計算幾何選手需要掌握的一個方法。

首先對於求解四邊形面積,我們可以將四邊形按對角線划分成兩個三角形,顯然此時四邊形的面積最大最小值就變成了求解里這個對角線最近最遠的點對。

對於此類問題有一個技巧,首先我們將點按照x為第一關鍵詞y為第二關鍵詞從小到大排序,然后我們開始取向量,並將所取的所有向量進行極角排序(斜率排序,叉積排序均可)。然后我們可以證明,第一條向量的兩個端點在之前排序過的點的序列中是相鄰的,如果這兩個不是相鄰的,說明中間存在一點並且滿足中間的點的x大於左端點小於右端點,此時我們可以畫圖得知,這樣會形成一條斜率更小的直線,與之前矛盾,所以這兩個端點在原序列中必然相鄰。接下來還有一個神奇的地方,這樣的序列保證在序列的第一個點到向量的左端點的點距離這條直線單調遞減,右側亦如此,如果存在一個點比前一個點的距離要遠,而這個點x大於前一個點的x,那么我們畫圖可知,這兩點的斜率比當前斜率要小,則矛盾,以此證明出這樣排序后的兩條性質,那么我們考慮當我們旋轉坐標系的時候,畫圖可知,受影響的點只有之前那條向量上的點,而且根據之前矛盾關系,之前那條的斜率大於現在這條,那么之前那條的兩端點到這條線上的距離一個小一個大,那么我們只需要更換這兩個點在序列中的位置,即可滿足之前的單調性,所以每次旋轉坐標系只需要交換上一條的向量兩端點在排序后的序列中的位置即可,這樣我們就維護出了距離對角線最遠和最近的點,那么求解最大最小四邊形面積也可以得出,當然也可以用此方法求得最大最小三角形面積,之前codeforce上有一題就是給定面積,去尋找是否存在三角形滿足面積等於給定值,那么我們便可以用這個單調性以此基礎上進行二分查找,所以此類方法復雜度為n2logn。

但是僅對於求解最大四邊形三角形面積,還有一個更優的策略,我們可以得出,四邊形上的四個點一定在凸包上,那么對於此類問題,我們便可以用旋轉卡殼進行枚舉,枚舉每一條對角邊,再用兩個點去旋轉,維護三角形最大值即可,對於三角形而言,三個端點仍然在凸包上,那么我們只需要固定一個點,旋轉下兩個端點即可,每次移動到該頂點處的三角形面最大位置即可,更新答案,此類方法復雜度nlogn

 

 1 //      ——By DD_BOND
 2 
 3 //#include<bits/stdc++.h>
 4 #include<functional>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<sstream>
 8 #include<iomanip>
 9 #include<climits>
10 #include<cstring>
11 #include<cstdlib>
12 #include<cstddef>
13 #include<cstdio>
14 #include<memory>
15 #include<vector>
16 #include<cctype>
17 #include<string>
18 #include<cmath>
19 #include<queue>
20 #include<deque>
21 #include<ctime>
22 #include<stack>
23 #include<map>
24 #include<set>
25 
26 #define fi first
27 #define se second
28 #define MP make_pair
29 #define pb push_back
30 #define INF 0x3f3f3f3f
31 #define pi 3.1415926535898
32 #define lowbit(a)  (a&(-a))
33 #define lson l,(l+r)/2,rt<<1
34 #define rson (l+r)/2+1,r,rt<<1|1
35 #define Min(a,b,c)  min(a,min(b,c))
36 #define Max(a,b,c)  max(a,max(b,c))
37 #define debug(x)  cerr<<#x<<"="<<x<<"\n";
38 
39 using namespace std;
40 
41 typedef long long ll; 42 typedef pair<int,int> P; 43 typedef pair<ll,ll> Pll; 44 typedef unsigned long long ull; 45 46 const ll LLMAX=2e18; 47 const int MOD=1e9+7; 48 const double eps=1e-12; 49 const int MAXN=1e6+10; 50 const int hmod1=0x48E2DCE7; 51 const int hmod2=0x60000005; 52 53 inline ll sqr(ll x){ return x*x; } 54 inline int sqr(int x){ return x*x; } 55 inline double sqr(double x){ return x*x; } 56 ll __gcd(ll a,ll b){ return b==0? a: __gcd(b,a%b); } 57 ll qpow(ll a,ll n){ll sum=1;while(n){if(n&1)sum=sum*a%MOD;a=a*a%MOD;n>>=1;}return sum;} 58 inline ll dcmp(ll x){ if(fabs(x)<eps) return 0; return (x>0? 1: -1); } 59 60 int p[2010]; 61 62 struct Point{ 63 int x,y,i,j; 64 Point(){ x=y=0; } 65 Point(int a,int b){ x=a,y=b; } 66 Point(int a,int b,Point p){ i=a,j=b,x=p.x,y=p.y; } 67 Point operator -(const Point &n)const{ return Point(x-n.x,y-n.y); } 68 bool operator <(const Point&n)const{ return x==n.x? y<n.y: x<n.x; } 69 void output(){ cout<<x<<' '<<y<<endl; } 70 }point[2010],vec[2*MAXN]; 71 72 ll cross(Point a,Point b){ return 1ll*a.x*b.y-1ll*a.y*b.x; } 73 74 ll check(int i,int j,int k){ return abs(cross(point[j]-point[i],point[k]-point[i])); } 75 76 int main(void) 77 { 78 ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 79  ll n; 80 while(cin>>n){ 81 ll s1=9e18,s2=0,cnt=0; 82 for(int i=0;i<n;i++) cin>>point[i].x>>point[i].y,p[i]=i; 83 if(n<4) return cout<<0<<' '<<0<<endl,0; 84 sort(point,point+n); 85 for(int i=0;i<n;i++) 86 for(int j=i+1;j<n;j++) 87 vec[cnt++]=Point(i,j,point[j]-point[i]); 88 sort(vec,vec+cnt,[](Point a,Point b){ return cross(a,b)>0; }); 89 for(int i=0;i<cnt;i++){ 90 int a=vec[i].i,b=vec[i].j; 91 if(p[a]>p[b]) swap(a,b); 92 if(p[a]!=0&&p[b]!=n-1) s2=max(s2,check(p[a],p[b],0)+check(p[a],p[b],n-1)); 93 if(p[a]!=0&&p[b]!=n-1) s1=min(s1,check(p[a],p[b],p[a]-1)+check(p[a],p[b],p[b]+1)); 94  swap(p[a],p[b]); swap(point[p[a]],point[p[b]]); 95  } 96 cout<<s1<<' '<<s2<<endl; 97  } 98 return 0; 99 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM