模板计几旋转坐标(用于最小三角形以及三角形四边形面积存在性问题)

Posted xiaobuxie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板计几旋转坐标(用于最小三角形以及三角形四边形面积存在性问题)相关的知识,希望对你有一定的参考价值。

发现计算几何算法(瞎搞)真的是博大精深。

最大三角形和最大四边形都是旋转卡壳,有模板的。这里的方法还可以求最小三角形还有最小四边形,以及三角形面积存在性问题。

求最小三角形面积(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
",ans);
64 }
View Code

 

接下来是求三角形面积存在性问题的: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
%lld %lld
%lld %lld",ans1.x,ans1.y,ans2.x,ans2.y,ans3.x,ans3.y);
73     }
74     else puts("No");
75     return 0;
76 }
View Code

以上是关于模板计几旋转坐标(用于最小三角形以及三角形四边形面积存在性问题)的主要内容,如果未能解决你的问题,请参考以下文章

计几算法补充

模板计几最大四边形

旋转卡壳模板

opengl绘图,画一个旋转的四边形和一个旋转的三角形,平滑着色和单一着色

Code Chef MINPOLY(计算几何+dp)

hdu1115多边形求重心模板