zoukankan      html  css  js  c++  java
  • 【xsy2305】喽 计算几何

    UPD:这个做法被hack了

    题目大意:给你$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
    ",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
    ");
    46     if(cnt==1) return printf("1
    ");
    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 }
  • 相关阅读:
    (CSDN迁移)js中的判空
    (CSDN迁移) 输入一个链表,从尾到头打印链表每个节点的值
    (CSDN迁移) 替换字符串中的空格
    (CSDN迁移) Java路径获取
    Apache JMeter 做接口并发测试
    用Postman做接口测试
    高并发或高负载下的系统设计
    编译时异常与运行时异常的区别
    使用JUNIT进行单元测试
    hexo 博客如何更换电脑
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10777609.html
Copyright © 2011-2022 走看看