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

news2024/10/5 19:12:49

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

往期相关背景点击前往

题目大意

题目链接
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)Xr
	auto 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 0

2
-1 0
-1 1

4
-1 0
-1 1
0 0
1 -1


10
1 2
5 8
7 6
-1 8
-8 9
-9 11
-3 -4
-5 7
8 7
9 10

10
-8 10
-7 9
-6 8
-10 0
-5 7
-4 6
-3 5
-2 4
-1 3
0 0

*/

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能-深度学习之残差网络(ResNet)

随着我们设计越来越深的网络&#xff0c;深刻理解“新添加的层如何提升神经网络的性能”变得至关重要。更重要的是设计网络的能力&#xff0c;在这种网络中&#xff0c;添加层会使网络更具表现力&#xff0c; 为了取得质的突破&#xff0c;我们需要一些数学基础知识。 ResNet沿…

计算机毕业设计基于java+springboot+vue的实验室管理系统

项目介绍 系统中的功能模块主要是实现管理员&#xff1b;首页、个人中心、实验室管理、用户管理、实验室申请管理、设备管理、设备报备管理、设备申请管理、消耗品管理、消耗品领取管理、论坛管理、系统管理&#xff0c;用户前台&#xff1b;首页、实验室、设备、消耗品、论坛…

MySQL-- INNODB 引擎

1、INNODB引擎的逻辑存储的结构&#xff1a; 第一层的逻辑结构&#xff1a;表空间 一个mysql实例可以对应多个表空间&#xff0c;用于存储记录&#xff0c;索引数据。 第二层逻辑结构&#xff1a;段 分为数据段、索引段、回滚段、innodb是索引组织表&#xff0c;数据段是BTre…

基于JavaWeb+SpringBoot+Vue电子商城微信小程序系统的设计和实现

基于JavaWebSpringBootVue电子商城微信小程序系统的设计和实现 源码获取入口前言系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 前言 身处互联网时代&#xff0c;互联网无形中影响着人们的吃穿住行&#xff0c;人们享受着不…

2024年春季3月退役的大学生士兵免试专升本单独报名的新政策

关于2024年春季3月退役大学生士兵专升本免试单独报名安排的通知 2024年3月退役的符合条件的大学生士兵单独组织一次报名&#xff0c;网上报名时间另行通知&#xff0c;履行网上报名和信息确认手续&#xff0c;根据要求上传本人头像照片、身份证照片&#xff0c;以及《入伍通知书…

WorkPlus Meet视频会议系统,可私有化部署,保障内部数据安全

WorkPlus Meet作为一款私有化音视频会议平台&#xff0c;具有高度安全性和部署灵活性&#xff0c;能够根据参会人数进行灵活的调配&#xff0c;这样企业可以有效控制会议成本&#xff0c;避免资源浪费。同时&#xff0c;WorkPlus Meet平台支持多种功能&#xff0c;满足不同场景…

做决策、定战略、带团队:顶级高手常用的16个思维模型

01 做决策 1.沃伦巴菲特的双目标清单系统&#xff08;Two-List System&#xff09; 弗林特当了巴菲特的私人飞行员十年之久&#xff0c;还曾为美国四任总统开过飞机&#xff0c;但他在事业上依然有更多追求。有一次&#xff0c;他和巴菲特在探讨他的职业生涯目标时&#xff0…

第三方软件测试服务有哪些形式?选择时如何避雷?

高新技术的快速发展&#xff0c;人们对于软件产品越来越依赖&#xff0c;因此软件质量对于软件企业来说至关重要。产品质量的好坏需要通过检测才得知&#xff0c;软件企业为了获得更客观公正的检验结果&#xff0c;会将软件测试交由第三方软件测试服务机构进行?那么有哪些形式…

python采集小破站视频弹幕

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 环境使用]: Python 3.8 Pycharm模块使用]: import requests 数据请求 import jieba 分词 import wordcloud 词云 import re 正则通过爬虫程序采集数据 分析数…

ubuntu22.04下hadoop3.3.6+hbase2.5.6+phoenix5.1.3开发环境搭建

一、涉及软件包资源清单 1、java 这里使用的是openjdk 2、hadoop-3.3.6.tar.gz 3、hbase-2.5.6-hadoop3-bin.tar.gz 4、phoenix-hbase-2.5-5.13-bin.tar.gz 5、apache-zookeeper-3.8.3-bin.tar.gz 6、openssl-3.0.12.tar.gz 二、安装 1、操作系统环境准备 换源 sudo vim /et…

小黑完成了最后一节健身课,顺利完成了跳绳比赛,乘飞机到达南京准备第二天领物资和南京城内闲逛的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 -…

Python数据结构:字典(dict)详解

1.字典概念 字典在其他语言中可能会被称为“关联存储”或“关联数组”。   在Python中&#xff0c;字典&#xff08;Dictionary&#xff09;是一种可变、无序且键值对&#xff08;key-value pairs&#xff09;唯一的数据结构。   字典也是一种标准映射类型&#xff0c;mapp…

ChatGPT助力高效办公——神奇的效率工具Airy

Airy是一款免费而又强大的高效办公软件&#xff0c;用户可以通过快捷键和丰富的内置插件&#xff0c;充分发挥GPT-3.5模型的强大功能&#xff0c;轻松实现搜索、翻译、文本生成与写作、文本概括与总结&#xff0c;同时还可以作为一款日程提醒工作&#xff0c;记录和提醒每天要做…

Linux编译器:gcc/g++的使用

我们在学习编译器时&#xff0c;我们不仅要只会使用编译器&#xff0c;还要理解程序的编译过程。一个程序存在两个不同的环境。第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令&#xff1b;第2种是执行环境&#xff0c;它用于实际执行代码。本篇文章将…

第十八章 Swing程序设计

Swing用于开发桌面窗体程序&#xff0c;是JDK的第二代GUI框架&#xff0c;其功能比JDK第一代GUI框架AWT更为强大、性能更加优良。但因为Swing技术推出时间太早&#xff0c;其性能、开发效率等不及一些其他流行技术&#xff0c;所以目前市场上大多数桌面窗体程序都不是由Java开发…

day18_多线程

今日内容 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、线程池 零、 复习昨日 见晨考 一、线程安全[重点] 1.0 线程不安全 当前线程的数据被其他线程修改 1.1 线程安全 临界资源&#xff1a;共享资源(同⼀个对象)&#xff0c;一次只可以有一个线程操…

JS-项目实战-代码优化-事件动态绑定

1、鼠标悬浮和离开事件.js //当页面加载完成后执行后面的匿名函数 window.onload function () {//get:获取 Element:元素 By:通过...方式//getElementById()根据id值获取某元素let fruitTbl document.getElementById("fruit_tbl");//table.rows:获取这个表格…

【Maven】进阶

文章目录 1. 聚合2. 继承3. 属性变量定义与使用4. 版本管理5. 资源配置6. 多环境配置7. 跳过测试&#xff08;了解&#xff09; 1. 聚合 为了防止某个模块&#xff08;dao&#xff09;更新了&#xff0c;重新编译了&#xff0c;导致和其他模块不兼容&#xff0c;需要用一个roo…

使用boost库

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;…

tsmc12 nm boundary cell注意事项

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 往期文章导读: boundary cell添加失败问题整理 注意N/P的区别 针对上下两边的boundary cell,有N/P类型的区别,看版图衬底形状上下是不对称的,而且P