正题

题目链接: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. .Net Core NPOI读取Excel 并转为数据实体类

    创建应用程序 这里直接创建Console程序 引用NPOI的NuGet包 PM> Install-Package NPOI -Version 2.5.1 直接Nuget包管理器添加 导入Exce ...

  2. 一 &#183; 路由事件的三种方式/策略(冒泡 直接 隧道)

    WPF中的路由事件是沿着VisualTree传递的,作用是用来调用应用程序的元素树上的各种监听器上的处理程序. (1)冒泡,这种事件处理方式是从源元素向上级流过去,直到到达根节点即顶层节点,一般为最外 ...

  3. 图解Win 10 应用开发之Sqlite 数据库的简单用法

    尽管目前 UWP-RT 库中还没有自带操作Sqlite数据库的API,不过,真要使用的话也不难,因为通过 Nuget ,我们其实可以获取很多支持 Sqlite 操作的第三方组件,当然了,组件虽多,但不 ...

  4. C#与.NET、CLR、CLI是什么关系?什么是.NET框架

    1.C#与.NET.CLR.CLI是什么关系?什么是.NET框架?      这个问题好专业啊!一句话两句话还真不好说清.您听说过C++中有个COM的概念吧?您听说过JAVA里的虚拟机吧?CLR(公共 ...

  5. 【C#】Enum,Int,String的互相转换 枚举转换

    Enum为枚举提供基类,其基础类型可以是除 Char 外的任何整型.如果没有显式声明基础类型,则使用 Int32.编程语言通常提供语法来声明由一组已命名的常数和它们的值组成的枚举. 注意:枚举类型的基 ...

  6. 使用dom4j工具:获取xml中的标签属性(三)

    package dom4j_read; import java.io.File; import java.util.List; import org.dom4j.Attribute; import o ...

  7. Gradient checking

    所需文件:本地下载 Gradient Checking Welcome to the final assignment for this week! In this assignment you wi ...

  8. Scan error on column index 1, name “created_at“: unsupported Scan, storing driver.Value type []uint8

    使用gorm,出现以下报错 在连接数据库时加上: parseTime=True db, err = gorm.Open(utils.Db, fmt.Sprintf("%s:%s@(%s:%s ...

  9. Linux·命令收藏

    时间:2018-11-20 记录:byzqy 标题:Linux命令大全(手册) 地址:http://man.linuxde.net/ 标题:Linux script命令 -- 终端里的记录器 地址:h ...

  10. MySQL-库表操作详述

    一.库操作 创建库 create database 库名(charset utf8 对库的编码进行设置,不写就用默认值) 库名可以由字母.数字.下划线.特殊字符,要区分大小写,唯一性,不能使用关键字, ...