xsy2305喽 计算几何

Posted xiefengze1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xsy2305喽 计算几何相关的知识,希望对你有一定的参考价值。

题目大意:给你$n$个红点和$m$个黑点,问你至少需要保留多少个黑点,才能用由黑点组成的凸包包住所有红点。

数据范围:$n≤10^5$,$m≤500$

 

首先,我们将红点和黑点丢到一起,求一个凸包。凸包上的点能用黑点就用黑点,否则才用红点。

所有重点,三点共线的点,都会被删除。

如果求出的凸包上有红点,那么显然是包不住的,直接输出-1即可。

我们将在凸包上的黑点找出。

 

设$nxt[i]$表示凸包上第$i$号节点,能在顺时针方向上删除多少个凸包上的点,使得凸包依然能包含住全部的红点。

如果我们求出了这个东西,我们显然可以在$O(m)$的时间复杂度内,求出最少需要多少个点。

 

考虑如何求$nxt[i]$

我们对于由$i$和$i+nxt[i]$构成的连线,如果是合法的,那么显然要满足凸包外侧没有任何点。

我们可以对所有红点,都用叉积判一遍就可以了。

更新$nxt[i]$的过程可以用类似旋转卡壳的方式来搞,单次均摊是$O(n)$的。

(我场上$sb$了居然在求凸包,虽然也可以判,但是它T了)

这么搞时间复杂度是$O(nm)$的,实际上跑得飞快。

时间复杂度为$O((n+m)\log\ (n+m)+nm)$

 

 1 #include<bits/stdc++.h>
 2 #define L long long
 3 #define M 110000
 4 #define INF 19890604
 5 using namespace std;
 6 
 7 struct node{
 8     L x,y;int type;
 9     void rd(int Type){type=Type; scanf("%lld%lld",&x,&y);}
10     node(){x=y=type=0;}
11     node(L X,L Y,int Type){x=X; y=Y; type=Type;}
12     friend node operator +(node a,node b){return node(a.x+b.x,a.y+b.y,0);}
13     friend node operator -(node a,node b){return node(a.x-b.x,a.y-b.y,0);}
14     friend L operator *(node a,node b){return a.x*b.y-a.y*b.x;}
15     friend bool operator ==(node a,node b){return a.x==b.x&&a.y==b.y;}
16 }a[M],s[M],b[505],all[M],bas=node(0,1e9,0);
17 int n,m,cnt=0,nm=0;
18 
19 bool cmp(node x,node y){
20     if(x.x==y.x&&x.y==y.y) return x.type<y.type;
21     return (x-bas)*(y-bas)>0;
22 }
23 void build(){
24     for(int i=1;i<=nm;i++) if(all[1].y>all[i].y) swap(all[1],all[i]);
25     bas=all[1]; sort(all+2,all+nm+1,cmp);
26     for(int i=1;i<=nm;i++){
27         while(cnt>1&&(s[cnt]-s[cnt-1])*(all[i]-s[cnt-1])<=0)
28         cnt--;
29         if(cnt>0&&s[cnt]==all[i]) cnt--;
30         s[++cnt]=all[i];
31     }
32 }
33 int nxt[M]={0},vis[M]={0};
34 int dfs(int x,int dep){
35     if(vis[x]) return printf("%d\n",dep-vis[x]);
36     vis[x]=dep;
37     dfs(nxt[x],dep+1);
38 }
39 
40 int main(){
41     scanf("%d%d",&n,&m);
42     for(int i=1;i<=n;i++) a[i].rd(1),all[++nm]=a[i];
43     for(int i=1;i<=m;i++) b[i].rd(2),all[++nm]=b[i];
44     build();
45     for(int i=1;i<=cnt;i++) if(s[i].type==1) return printf("-1\n");
46     if(cnt==1) return printf("1\n");
47     memset(b,0,sizeof(b)); m=cnt;
48     for(int i=1;i<=m;i++) b[i]=b[i+cnt]=s[i];
49     for(int i=1,j=1;i<=m;i++){
50         while(1){
51             if(j==i) j++;
52             for(int k=1;k<=n;k++)
53             if((a[k]-b[i])*(b[j]-b[i])>0)
54             goto loop;
55             j++;
56         }
57         loop:;
58         nxt[i]=(j-2+m)%m+1;
59     }
60     dfs(1,1);
61 }

以上是关于xsy2305喽 计算几何的主要内容,如果未能解决你的问题,请参考以下文章

计算片段着色器内平面的法线

如果几何着色器处于活动状态,如何将信息从顶点着色器传递到片段着色器?

计算几何模板中的代码

仅仅三行JAVA代码计算多边形的几何中心点

仅仅三行JAVA代码计算多边形的几何中心点

计算几何——凸包问题