题目链接https://vjudge.net/problem/UVA-13024

题意:先给出\(L\)个点构造一个凸包,再给出\(S\)个点,询问有几个点在凸包内。

题解:判断点是否在凸包内的模板题。最暴力的想法是\(o(n^2)\)枚举每个点,但实际上我们可以使用二分优化。具体操作就是以凸包最左侧点为起点,对每个点按斜率排序,然后把凸包分割成数个三角形,在这些三角形中二分查找斜率。复杂度便优化为\(o(nlogn)\)如下图。

  • 在凸包\(ABCDEFG\)中可二分查找\(H\),\(I\),\(J\),\(K\)点

完成二分后,通过叉积判断点是否在凸包内,如下图。

  • \(\vec{FH}\times{\vec {HE}} < 0\),\(\vec{FK}\times{\vec {KE}} > 0\)

即叉积<0则在凸包内,>0在凸包外,同时还有叉积=0的情况(点在凸包的边上)。但是叉积=0时还应考虑一种情况,即在凸包一条边的延长线上,需要特判。如下图。

  • 如图所示的\(L\)点和\(M\)点叉积均为0。

AC代码

#include <bits/stdc++.h>
#define SIZE 100007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
ll n, m, t, num;
struct Point {
ll x, y;
double k;
friend bool operator<(const Point& a, const Point& b) { //为使用lower_bound进行运算符重载
return a.k <= b.k;
}
};
Point p[SIZE], ch[SIZE], tp[SIZE];
bool cmp(Point a, Point b) { //andrew算法排序预处理函数
if (a.x == b.x) return a.y < b.y;
else return a.x < b.x;
}
ll cross(Point a, Point b, Point c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); }
ll crossx(Point a, Point b, Point c) { return (a.x - b.x) * (c.y - a.y) - (a.y - b.y) * (c.x - a.x); }
ll andrew() { //采用安德鲁算法求凸包,返回顶点数
sort(p + 1, p + n + 1, cmp);
ll top = 0;
for (int i = 1; i <= n; ++i) {
while ((top > 1) && (cross(ch[top - 1], ch[top], p[i]) <= 0)) --top;
ch[++top] = p[i];
}
ll tmp = top;
for (int i = n - 1; i; --i) {
while ((top > tmp) && (cross(ch[top - 1], ch[top], p[i]) <= 0)) --top;
ch[++top] = p[i];
}
if (n > 1) top--;
return top;
}
bool InConvexHull(ll top, Point x) { //判断点x是否在凸包内
ll pos = lower_bound(ch + 1, ch + top + 1, x) - ch - 1; //二分查找
if (pos == 1) return false;
ll j = crossx(x, ch[pos], ch[pos + 1]);
if (j < 0) return true;
else if (j == 0) { //叉积为0时特判
ll minx = min(ch[pos].x, ch[pos + 1].x), maxx = max(ch[pos].x, ch[pos + 1].x);
ll miny = min(ch[pos].y, ch[pos + 1].y), maxy = max(ch[pos].y, ch[pos + 1].y);
if ((minx <= x.x) && (maxx >= x.x) && (miny <= x.y) && (maxy >= x.y)) return true;
else return false;
}
else return false;
}
int main() {
io();
while (cin >> n && n) { //多组输入
num = 0;
rep(i, 1, n) cin >> p[i].x >> p[i].y;
cin >> m;
ll top = andrew();
ll x = ch[1].x, y = ch[1].y;
rep(i, 2, top) { //计算斜率
double tx = ch[i].x - x, ty = ch[i].y - y;
if (!tx) { //若x坐标相同,则斜率设为1e18
if (ty < 0) ch[i].k = -1e18;
else ch[i].k = 1e18;
}
else ch[i].k = 1.0 * ty / tx;
}
ch[1].k = -1e18;
rep(i, 1, m) {
cin >> tp[i].x >> tp[i].y;
if (ch[1].x > tp[i].x) continue;
ll tx = tp[i].x - x, ty = tp[i].y - y;
Point x;
if (!tx) {
if (ty < 0) x.k = -1e18;
else x.k = 1e18;
}
else x.k = 1.0 * ty / tx;
x.x = tp[i].x, x.y = tp[i].y;
if (InConvexHull(top, x)) ++num; //计数
}
cout << num << endl;
}
}

UVA - 13024 Saint John Festival 凸包+二分的更多相关文章

  1. UVA 13024: Saint John Festival(凸包+二分 ,判定多个点在凸包内)

    题意:给定N个点,Q次询问,问当前点知否在N个点组成的凸包内. 思路:由于是凸包,我们可以利用二分求解. 二分思路1:求得上凸包和下凸包,那么两次二分,如果点在对应上凸包的下面,对应下凸包的上面,那么 ...

  2. Saint John Festival Gym - 101128J (凸包二分)

    Problem J: Saint John Festival \[ Time Limit: 1 s \quad Memory Limit: 256 MiB \] 题意 给出\(n\)个大点,和\(m\ ...

  3. UVALive 7281 Saint John Festival (凸包+O(logn)判断点在凸多边形内)

    Saint John Festival 题目链接: http://acm.hust.edu.cn/vjudge/contest/127406#problem/J Description Porto's ...

  4. Gym 101128J Saint John Festival(凸包 + 二分判点和凸包关系)题解

    题意:给你一堆黑点一堆红点,问你有最多几个黑点能找到三个红点,使这个黑点在三角形内? 思路:显然红点组成的凸包内的所有黑点都能做到.但是判断黑点和凸包的关系朴素方法使O(n^2),显然超时.那么我现在 ...

  5. 【计算几何】【凸包】【极角排序】【二分】Gym - 101128J - Saint John Festival

    平面上n个红点,m个黑点,问你多少个黑点至少在一个红三角形内. 对红点求凸包后,转化为询问有多少个黑点在凸包内. 点在凸多边形内部判定,选定一个凸包上的点作原点,对凸包三角剖分,将其他的点极角排序之后 ...

  6. 15-16 ICPC europe J Saint John Festival (graham扫描法+旋转卡壳)

    题意:给n个大点,m个小点$(n<=1e5,m<=5e5),问有多少个小点,存在3个大点,使小点在三个大点组成的三角形内. 解题思路: 首先,易证,若该小点在某三大点行成的三角形内,则该小 ...

  7. 【bzoj3203】[Sdoi2013]保护出题人 凸包+二分

    题目描述 输入 第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离.接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和 Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的 ...

  8. 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分

    题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...

  9. 训练指南 UVA - 11478(最短路BellmanFord+ 二分+ 差分约束)

    layout: post title: 训练指南 UVA - 11478(最短路BellmanFord+ 二分+ 差分约束) author: "luowentaoaa" catal ...

随机推荐

  1. 剑指offer 面试题 删除链表中重复的节点

    题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后 ...

  2. leetcode 1214 Two Sum BSTs

    function rob(a, b, target) { var hash = {} var stack = [a] while (queue.length) { var node = stack.p ...

  3. CSS遮罩层简易写法

      现在很多站点弹出框,都需要一个遮罩层.写法很多,以下是我比较喜欢的一种: .box{ position:absolute; top:0; bottom:0; left:0; right:0; ba ...

  4. Sobel边缘检测算法

    索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值.在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量 Sobe ...

  5. mybatis(六):设计模式 - 责任链模式

  6. C++-POJ3274-Gold Balanced Lineup[hash]

    不是很懂? 胡乱hash #include <set> #include <map> #include <cmath> #include <queue> ...

  7. 微信h5游戏如何在微信中做好域名防封 防屏蔽的 工作

    最近微信开始大封杀,不知道原因是什么,可能是因为违规网站太多了吧,很多网站都被错杀了,下面我们聊一下怎样才能避免域名被封杀呢. 在各种不同的域名当中,能够做出了更适合的选择,这些对于大家域名防封_域名 ...

  8. Flink读写Kafka

    Flink 读写Kafka 在Flink中,我们分别用Source Connectors代表连接数据源的连接器,用Sink Connector代表连接数据输出的连接器.下面我们介绍一下Flink中用于 ...

  9. Apache Kafka(十二)Log Cleanup 策略

    Log Cleanup 策略 在Kafka中,存在数据过期的机制,称为data expire.如何处理过期数据是根据指定的policy(策略)决定的,而处理过期数据的行为,即为log cleanup. ...

  10. sourcetree(mac)设置代理

    Mercurial: edit ~/.hgrcas shown here: http://www.selenic.com/mercurial/hgrc.5.html#http-proxy Git: e ...