半平面求交 - 洛谷 - P3194 [HNOI2008] 水平可见直线

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

往期相关背景点击前往

题目大意

题目链接
https://www.luogu.com.cn/problem/P3194

在直角坐标系中给定一些直线,然后从Y轴无穷大处往0处看,问可以看到哪些直线。

在这里插入图片描述

解析

在这里插入图片描述
通过观察可以发现,能看到的直线会形成一个开口凸包。

可以先对直线进行方向规定向右,然后进行半平面求交,凸包有效的边就是可以看到的直线。

代码

#include<stdio.h>
#include<cmath>
#include <algorithm>
#include <vector>
#include <list>
#include <cstring>
#include <deque>using namespace std;
const double EPS = 1e-12;const int N = 1e6 + 10;
const int M = 1e6 + 10;int cmp(double d) {if (abs(d) < EPS)return 0;if (d > 0)return 1;return -1;
}class Point {
public:double x, y;int id;Point() {}Point(double a, double b) :x(a), y(b) {}Point(const Point& p) :x(p.x), y(p.y), id(p.id) {}void in() {scanf("%lf %lf", &x, &y);}void out() {printf("%f %f\n", x, y);}double dis() {return sqrt(x * x + y * y);}double dis2() {return x * x + y * y;}Point operator -() const {return Point(-x, -y);}Point operator -(const Point& p) const {return Point(x - p.x, y - p.y);}Point operator +(const Point& p) const {return Point(x + p.x, y + p.y);}Point operator *(double d)const {return Point(x * d, y * d);}Point operator /(double d)const {return Point(x / d, y / d);}void operator -=(Point& p) {x -= p.x;y -= p.y;}void operator +=(Point& p) {x += p.x;y += p.y;}void operator *=(double d) {x *= d;y *= d;}void operator /=(double d) {this ->operator*= (1 / d);}bool operator<(const Point& a) const {return x < a.x || (abs(x - a.x) < EPS && y < a.y);}bool operator==(const Point& a) const {return abs(x - a.x) < EPS && abs(y - a.y) < EPS;}
};// 向量操作double cross(const Point& a, const Point& b) {return a.x * b.y - a.y * b.x;
}double dot(const Point& a, const Point& b) {return a.x * b.x + a.y * b.y;
}class Line {
public:Point front, tail;int ind;Line() {}Line(const Point& a, const Point& b) :front(a), tail(b) {}Line(const Point& a, const Point& b, int i) :front(a), tail(b), ind(i) {}
};int cmp(const Line& a, const Line& b) {auto ta = atan2(a.front.y - a.tail.y, a.front.x - a.tail.x);auto tb = atan2(b.front.y - b.tail.y, b.front.x - b.tail.x);return cmp(ta - tb);
}// 点在直线哪一边>0 左边,<0边
int SideJudge(const Line& a, const Point& b) {return cmp(cross(a.front - a.tail, b - a.tail));
}int LineSort(const Line& a, const Line& b) {int c = cmp(a, b);if (c)return c < 0;return SideJudge(b, a.front) > 0;
}/*
点p 到 p+r 表示线段1
点q 到 q+s 表示线段2
线段1 上1点用 p' = p+t*r (0<=t<=1)
线段2 上1点用 q' = q+u*s (0<=u<=1)
让两式相等求交点 p+t*r = q+u*s
两边都叉乘s
(p+t*r)Xs = (q+u*s)Xs
pXs + t*rXs = qXs
t = (q-p)Xs/(rXs)
同理,
u = (p-q)Xr/(sXr) -> u = (q-p)Xr/(rXs)以下分4种情况:
1. 共线,sXr==0 && (q-p)Xr==0, 计算 (q-p)在r上的投影在r长度上的占比t0,
计算(q+s-p)在r上的投影在r长度上的占比t1,查看[t0, t1]是否与范围[0,1]有交集。
如果t0>t1, 则比较[t1, t0]是否与范围[0,1]有交集。
t0 = (q-p)*r/(r*r)
t1 = (q+s-p)*r/(r*r) = t0 + s · r / (r · r)
2. 平行sXr==0 && (q-p)Xr!=0
3. 0<=u<=1 && 0<=t<=1 有交点
4. 其他u, t不在0到范围内,没有交点。
*/
pair<double, double> intersection(const Point& q, const Point& s, const Point& p, const Point& r) {// 计算 (q-p)Xrauto qpr = cross(q - p, r);auto qps = cross(q - p, s);auto rXs = cross(r, s);if (cmp(rXs) == 0)return { -1, -1 }; // 平行或共线// 求解t, u// t = (q-p)Xs/(rXs)auto t = qps / rXs;// u = (q-p)Xr/(rXs)auto u = qpr / rXs;return { u, t };
}Point LineCross(const Line& a, const Line& b) {Point dira = a.front - a.tail;Point dirb = b.front - b.tail;auto p = intersection(a.tail, dira, b.tail, dirb);return a.tail + dira * p.first;
}class HalfPlane {
public:vector<Line> lines;void addLine(const Line& a) {lines.push_back(a);}vector<int> run() {sort(lines.begin(), lines.end(), LineSort);vector<int> q(lines.size() + 10);vector<Point> t(lines.size() + 10);int l = -1, r = 0;q[0] = 0;for (int i = 1; i < lines.size(); ++i) {if (cmp(lines[i], lines[i - 1]) == 0)continue;while (r - l > 1 && SideJudge(lines[i], t[r]) <= 0)r--;while (r - l > 1 && SideJudge(lines[i], t[l + 2]) <= 0)l++;q[++r] = i;t[r] = LineCross(lines[q[r]], lines[q[r - 1]]);}/*while (r - l > 1 && SideJudge(lines[q[l + 1]], t[r]) < 0)r--;t[r+1] = LineCross(lines[q[l+1]], lines[q[r]]);r++;*/// 统计交点/*l++;vector<Point> ans(r-l);for (int i = 0; i < ans.size(); ++i) {ans[i] = t[i + l + 1];}*/vector<int> ans;for (int i = l + 1; i <= r; ++i) ans.push_back(lines[q[i]].ind);sort(ans.begin(), ans.end());return ans;}
};Point oiPs[N];void  solve() {int n;scanf("%d", &n);HalfPlane hp;int a, b;for (int i = 0; i < n; ++i) {scanf("%d%d", &a, &b);Line l(Point(1, a + b), Point(0, b), i + 1);hp.addLine(l);}auto ans = hp.run();for (auto x : ans) printf("%d ", x);
}int main() {solve();return 0;}/*
1
0 02
-1 0
-1 14
-1 0
-1 1
0 0
1 -110
1 2
5 8
7 6
-1 8
-8 9
-9 11
-3 -4
-5 7
8 7
9 1010
-8 10
-7 9
-6 8
-10 0
-5 7
-4 6
-3 5
-2 4
-1 3
0 0*/

本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/178646.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iis特殊字符的轉義問題解決

今天發現有個問題&#xff0c;部分圖片的靜態資源帶有號&#xff0c;導致無法直接在瀏覽器獲取圖片&#xff0c;百度了一下&#xff0c;修改了注冊表&#xff0c;發現沒什麽軟用&#xff0c;最後找到一篇博客&#xff0c;解決了 解決

WorkPlus私有化部署的即时通讯软件,企业内部沟通协作的利器

随着企业的成长和信息科技的进步&#xff0c;团队协作变得越来越关键。为了更好地促进团队之间的信息共享和沟通&#xff0c;企业内部对聊天软件的需求也在不断增加。 WorkPlus是一个支持海量用户和高并发的私有化部署即时通讯能力&#xff0c;支持纯内网&#xff0c;内外网混…

服务号转订阅号如何操作

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;一、文章推送的篇数不同服务号在文章的推送篇数上是有所限制的&#xff08;每月推4次&#xff09;订阅号则每天可推送一篇文章。二、定义不同服务号主要是为关注用户提供服务使用的&#xff1b;订阅…

数据结构-数型查找

二叉排序树&#xff08;BST&#xff09; 二叉排序树&#xff0c;又称二叉查找树&#xff08;BST&#xff0c;Binary Search Tree&#xff09; 一颗二叉树或者是空二叉树&#xff0c;或者是具有如下性质的二叉树&#xff1a; 左子树上所有结点的关键字均小于根结点的关键字&…

Axure9 基本操作(一)

产品经理零基础入门&#xff08;四&#xff09;Axure 原型图教程&#xff0c;2小时学会_哔哩哔哩_bilibili Axure 9 从入门到精通全集&#xff0c;自学必备_哔哩哔哩_bilibili 1. 页面对应页面个数&#xff0c;概要对应每个页面的具体内容 2. 文件类型 3. 备用间隔改为5分钟 …

SOLIDWORKS 2024新功能之Visualize篇

SOLIDWORKS 2024新功能Visualize 增强了创建引人注目的外观的功能 SOLIDWORKS Visualize 使用 Dassault Systmes 的企业 PBR 着色模型 (DSPBR) 来准确复制金属、玻璃、塑料和其他曲面的逼真外观。 DSPBR 是材料模型&#xff0c;用于基于物理的渲染&#xff0c;受 3DEXPERIENCE…

如何在面试中胜出?接口自动化面试题安排上

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

【算法与数据结构】78、90、LeetCode子集I, II

文章目录 一、题目二、78.子集三、90.子集II三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、78.子集 思路分析&#xff1a;【算法与数据结构】77、LeetCode组合。本题可以参考77题的组合问题代码&#xff0…

小黑完成了最后一节健身课,顺利完成了跳绳比赛,乘飞机到达南京准备第二天领物资和南京城内闲逛的leetcode之旅:215. 数组中的第K个最大元素

小黑代码 class Solution:def findKthLargest(self, nums: List[int], k: int) -> int:# 数组长度n len(nums)nums list(map(lambda x:-x, nums))q []for i in range(n):heapq.heappush(q, nums[i])# 出堆target -1for i in range(k):target heapq.heappop(q)return -…

Matter 协议详解

目录 1、Matter 协议发展 1.1、什么是Matter 1.2、Matter能做什么 2、整体介绍 3、架构介绍 3.1、Matter网络拓扑结构 3.2、标识符 3.2.1、Fabric引用和Fabric标识符 3.2.2、供应商标识符&#xff08;Vendor ID&#xff0c;VID&#xff09; 3.2.3、产品标识符&#x…

postswigger 靶场(CSRF)攻略-- 2.令牌验证

靶场地址&#xff1a; What is CSRF (Cross-site request forgery)? Tutorial & Examples | Web Security Academy (portswigger.net)https://portswigger.net/web-security/csrf 令牌(token)验证取决于请求方法 题目中已告知易受攻击的是电子邮件的更改功能&#xff0…