正题

题目链接:https://www.ybtoj.com.cn/contest/116/problem/3


题目大意

给出两个大小分别为\(n,m\)的点集\(A,B\)。

求出\(B\)的一个最小子集使得该子集的凸包包含了所有点集\(A\)中的点。

无解输出\(-1\)

\(2\leq n\leq 10^5,3\leq m\leq 500\)


解题思路

选出的子集肯定是一个凸包,凸包就是相邻点连边之间的半平面交。

所以可以理解为我们要找到一些点对使得它们的半平面包含点集\(A\)。

如果\(x->y\)的半平面(左右都一样,反过来就是了)包含点集\(A\),那么\(x\)向\(y\)连边,那么问题就变为了求图的最小环。这个可以\(Floyd\)解决。

如何判断一个半平面是否包含点集\(A\)?

一个类似旋转卡壳的想法是对于给出的这个半平面的斜率,我们在点集\(A\)的凸包上找到两个节点卡住它。(如下图)



然后判断这两个点是否在半平面内就好了。

挺麻烦的,再简化一下,我们将\(A\)的凸包用\(x\)坐标最大/小的两个节点分成两半,那么凸包就变成了一个上凸壳和一个下凸壳。

然后我们要找到的两个点,这个两个点肯定是一个在上一个在下的,我们根据半平面的斜率在上下凸壳上面二分一下就好了。

时间复杂度\(O(n+m^2\log n+m^3)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10,M=510;
struct point{
ll x,y;
point(ll xx=0,ll yy=0)
{x=xx;y=yy;return;}
}g[N],u[N],v[N],s[N],p[M];
ll n,m,uc,vc,f[M][M],h[M][M],ans;
point operator+(point a,point b)
{return point(a.x+b.x,a.y+b.y);}
point operator-(point a,point b)
{return point(a.x-b.x,a.y-b.y);}
ll operator*(point a,point b)
{return a.x*b.y-a.y*b.x;}
ll solve(point *a,ll n,ll op){
ll top;s[top=1]=a[1];
for(ll i=2;i<=n;i++){
while(top>1&&(s[top]-s[top-1])*(a[i]-s[top-1])*op>=0)top--;
s[++top]=a[i];
}
for(ll i=1;i<=top;i++)
a[i]=s[i];
return top;
}
bool check(point a,point b){
ll op=1;
if(a.x>b.x)swap(a,b),op=-1;
ll l=1,r=uc-1;
while(l<=r){
ll x=(l+r)>>1;
if((b-a)*(u[x+1]-u[x])>=0)l=x+1;
else r=x-1;
}
if((b-a)*(u[l]-a)*op<0)return 0;
l=1,r=vc-1;
while(l<=r){
ll x=(l+r)>>1;
if((b-a)*(v[x+1]-v[x])<=0)l=x+1;
else r=x-1;
}
if((b-a)*(v[l]-a)*op<0)return 0;
return 1;
}
bool cmp(point a,point b)
{return a.x<b.x;}
signed main()
{
freopen("lo.in","r",stdin);
freopen("lo.out","w",stdout);
scanf("%lld%lld",&n,&m);
ll L=1,R=1;
for(ll i=1;i<=n;i++)
scanf("%lld%lld",&g[i].x,&g[i].y);
sort(g+1,g+1+n,cmp);
for(ll i=1;i<=n;i++){
ll w=(g[n]-g[1])*(g[i]-g[1]);
if(w>=0)u[++uc]=g[i];
if(w<=0)v[++vc]=g[i];
}
uc=solve(u,uc,1);
vc=solve(v,vc,-1);
for(ll i=1;i<=m;i++)
scanf("%lld%lld",&p[i].x,&p[i].y);
for(ll i=1;i<=m;i++)
for(ll j=1;j<=m;j++){
if(i==j){h[i][j]=f[i][j]=1e9;continue;}
h[j][i]=f[i][j]=check(p[i],p[j])?1:1e9;
}
for(ll k=1;k<=m;k++)
for(ll i=1;i<=m;i++)
for(ll j=1;j<=m;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
ans=1e9;
for(ll i=1;i<=m;i++)
for(ll j=1;j<=m;j++)
ans=min(ans,f[i][j]+h[i][j]);
if(ans>=1e9)puts("-1");
else printf("%lld\n",ans);
return 0;
}

YbtOJ#832-鸽子饲养【凸包,Floyd】的更多相关文章

  1. 7.1 NOI模拟赛 凸包套凸包 floyd 计算几何

    计算几何之所以难学 就是因为太抽象了 不够直观 而且情况很多 很繁琐 甚至有一些东西不清不楚.. 这道题注意到题目中的描述 一个鸽子在两个点所连直线上也算. 通过看题解 发现这个地方并非直线而是线段 ...

  2. 【BZOJ】1027: [JSOI2007]合金(凸包+floyd)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1027 题意:$n$种材料,$m$种需求.每种材料有三个属性,给出三个属性的含量(和为1),问能否通过 ...

  3. 【BZOJ 1027】 (凸包+floyd求最小环)

    [题意] 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金 ...

  4. bzoj 1027: [JSOI2007]合金【凸包+Floyd】

    参考:https://www.cnblogs.com/zhuohan123/p/3237246.html 因为一c可以由1-a-b得出,所以删掉c,把a,b抽象成二维平面上的点.首先考虑一个客户需求能 ...

  5. 【BZOJ】【1027】【JSOI2007】合金

    计算几何/凸包/Floyd Orz rausen大爷太强辣 计算几何题目果然不会做>_> 这个题……虽然他给了3个坐标,但实际上是个二维的计算几何题= =因为第三维坐标可以直接用前两维坐标 ...

  6. 【JZOJ5094】【GDSOI2017第四轮模拟day3】鸽子 计算几何+floyd

    题面 养鸽人要监视他的鸽子,有n只鸽子站在平面上,他可以在m个给定的点上设置监视器,如果一只鸽子在某个监视器上或者在两个监视器所连直线上或者在三个监视器所连直线的三角形内则其就咕咕咕了,现在养鸽人要让 ...

  7. BZOJ1390 CEOI2008 Fences 凸包、Floyd最小环/DP

    传送门 为了方便描述把固定点叫做白色点,Tree叫做黑色点 一种基于特殊性质的做法: 如果不算入选白色的权值,那么一定会选中所有白色点构成的凸包上的点,因为能够尽可能围更多的黑色点.然后我们在这个基础 ...

  8. HDU - 6080 :度度熊保护村庄 (凸包,floyd最小环)(VJ1900题达成)

    pro:二维平面上,给定N个村庄.M个士兵驻守,把村庄围住,现在我们想留下更多的士兵休息,使得剩下的士兵任然满足围住村庄.N,M<500: sol:即是要找一个最小的环,环把村庄围住. 由于是环 ...

  9. bzoj 1027 [JSOI2007]合金(计算几何+floyd最小环)

    1027: [JSOI2007]合金 Time Limit: 4 Sec  Memory Limit: 162 MBSubmit: 2970  Solved: 787[Submit][Status][ ...

随机推荐

  1. c# 执行python方法

    在C#使用Python脚本文件要注意的的是,首先要将IronPython2.7安装路径中的两个dll文件添加到C#引用中一个是IronPython.dll,另一个是Microsoft.Scriptin ...

  2. 判断N是否是质数,为什么判断到根号N就可以了

    N=根号N*根号NN的因数除了根号N,其他都是成对存在的, 且必定一个大于根号N一个小于根号N假设N不是质数,有个因数大于根号N(不是N本身) 则N必定有一个与之对应的小于根号N的因数也就是说,如果2 ...

  3. C++ 矩形交集和并集的面积-离散化

    //离散化,x,y坐标分别按从小到大排序 //离散化 //1.首先分离出所有的横坐标和纵坐标分别按升序存入数组X[ ]和Y[ ]中. //2. 设数组XY[ ][ ].对于每个矩形(x1,y1)(x2 ...

  4. Dijkstra链路状态选路算法

  5. Flink Data transformation(转换)

    Flink Data transformation 算子学习 1.Source:数据源,Flink在流处理和批处理上的source大概有4类: 基于本地集合的source.基于文件的source.基于 ...

  6. spring boot应用常用配置

    pom.xml <!--自动打包--> <plugin> <groupId>org.springframework.boot</groupId> < ...

  7. Dapper同时操作任意多张表的实现

    1:Dapper的查询帮助类,部分代码,其它新增更新删除可以自行扩展 using Microsoft.Extensions.Configuration; using System; using Sys ...

  8. 分布式协调组件Zookeeper之 选举机制与ZAB协议

    Zookeeper简介: Zookeeper是什么: Zookeeper 是⼀个分布式协调服务的开源框架. 主要⽤来解决分布式集群中应⽤系统的⼀致性问题, 例如怎样避免同时操作同⼀数据造成脏读的问题. ...

  9. Redis cluster的部署

    Redis 集群是一个提供在多个Redis间节点间共享数据的程序集. Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下 ...

  10. Springboot_Email注解爆红

    应该是更新后的版本,不会自动导入pom依赖 <!--新版本需要validation启动器 --> <dependency> <groupId>org.springf ...