ACM刷题之路(六)直线相交问题 POJ3304 Segments

简介: ACM刷题之路(六)直线相交问题 POJ3304 Segments

题目链接:http://poj.org/problem?id=3304

题目:

Description

Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments on it, all projected segments have at least one point in common.

Input

Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing a positive integer n ≤ 100 showing the number of segments. After that, n lines containing four real numbers x1 y1 x2 y2 follow, in which (x1, y1) and (x2, y2) are the coordinates of the two endpoints for one of the segments.

Output

For each test case, your program must output "Yes!", if a line with desired property exists and must output "No!" otherwise. You must assume that two floating point numbers a and b are equal if |a - b| < 10-8.

Sample Input

1. 3
2. 2
3. 1.0 2.0 3.0 4.0
4. 4.0 5.0 6.0 7.0
5. 3
6. 0.0 0.0 0.0 1.0
7. 0.0 1.0 0.0 2.0
8. 1.0 1.0 2.0 1.0
9. 3
10. 0.0 0.0 0.0 1.0
11. 0.0 2.0 0.0 3.0
12. 1.0 1.0 2.0 1.0

Sample Output

1. Yes!
2. Yes!
3. No!

 

题目大意:

3( t   组数)

2  (n  接下来有n条线段)

1.0 2.0 3.0 4.0   (分别是x1,y1,x2,y2)

4.0 5.0 6.0 7.0

问 是否存在一条直线,使得该直线和所有以上线段都相交。

首先,我们来看点积的几何意义:

设存在a向量和b向量

a·b>0    则a、b向量方向相同;

a·b=0   则a、b向量相互垂直;

a·b<0   则a、b向量方向相反;

 

此时聪明的读者已经明白,叉积也有它的几何意义:

设存在点P1,P2,P3;(因为赶高铁时间紧,直接放图片)

跟线性代数求行列式一样,叉积的计算方法就是求行列式

因为叉积的结果是向量,我们只需要判断结果向量的正负性即可,所以我们忽略单位i和j,(因为i、j都是单位向量且方向是正)

所以只要写一个函数,判断正负性即可,代码如图片下:

1. double det(Point p1,Point p2,Point p3)
2. {
3. return (p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y);//判断点p3是否在线段p1p2的左右
4. //  x1y2+x3y1+x2y3-x3y2-x2y1-x1y3  不要这样直接乘..可能会爆掉
5. }

该代码是计算叉积。

如果a叉积b大于0  则p2p3 在p1p3的逆时针方向反之是顺时针方向。

 

接着  ,聪明的读者已经知道,一条线段只要两个端点在一条直线的一边(不包括边上),则线段和直线不相交,反之相交。

一条直线,可以平动和转动,只要满足四种情况的其中之一就可以达到题目的要求。

只要四种极端情况满足(  除这两个点构成的线段以外的所有线段都和该直线相交  )这个条件,就可以输出yes了,否则输出no。

代码如下:

1. int judge(Point p1,Point p2)
2. {
3. if(abs(p1.x-p2.x) < MIN && abs(p1.y-p2.y) < MIN)
4. return 0;
5. for(int i=0; i<n; i++)
6. if(det(p1, p2, Left[i])*det(p1, p2, Right[i]) > MIN) return 0;//每个点都进行判断
7. return 1;
8. }

总的代码在下面:

聪明的读者已经明白

1. #include<iostream>
2. #include<cmath>
3. #include <stdio.h>
4. #include <set>
5. #include <map>
6. #include <algorithm>
7. using namespace std;
8. 
9. #define MAX 150
10. #define MIN 1e-8
11. int n;
12. struct Point{
13. double x, y;
14. } Left[MAX], Right[MAX]; //端点存入数组
15. 
16. double det(Point p1, Point p2, Point p3){
17. return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);//判断点p3是否在线段p1p2的左右
18. //  x1y2+x3y1+x2y3-x3y2-x2y1-x1y3  不要这样直接乘..可能会爆掉
19. }
20. 
21. int judge(Point p1, Point p2){
22. if (abs(p1.x - p2.x) < MIN && abs(p1.y - p2.y) < MIN)
23. return 0;
24. for (int i = 0; i < n; i++) {
25. if (det(p1, p2, Left[i]) * det(p1, p2, Right[i]) > MIN)
26. return 0;//每个点都进行判断
27.     }
28. return 1;
29. }
30. int main()
31. {
32. int T, result;
33. scanf("%d", &T);
34. while (T--){
35. scanf("%d", &n);
36. for (int i = 0; i < n; i++){
37. scanf("%lf%lf%lf%lf", &Left[i].x, &Left[i].y, &Right[i].x, &Right[i].y);
38.         }
39.         result = 0;
40. if (n < 3) result = true;//小于三条线段 肯定能够找到一条直线满足条件
41. for (int i = 0; i < n; i++){
42. for (int j = i + 1; j < n; j++) { //从i+1开始 因为之前的情况已经枚举过
43. if (result) break;
44. if (judge(Left[i], Left[j])) result = 1;
45. else if (judge(Left[i], Right[j])) result = 1;
46. else if (judge(Right[i], Left[j])) result = 1;
47. else if (judge(Right[i], Right[j])) result = 1;
48.             }
49. if (result) break;
50.         }
51. if (result) printf("Yes!\n");
52. else printf("No!\n");
53.     }
54. return 0;
55. }


相关文章
|
编译器 API C++
c++ 新特性 概念和约束 “无规矩 难成方圆”
c++ 新特性 概念和约束 “无规矩 难成方圆”
155 1
|
5月前
|
存储 弹性计算 资源调度
阿里云服务器收费模式对比:包年包月与按量付费的适用场景与选择参考
在我们购买阿里云服务器的时候,云服务器的收费模式主要有多种收费模式,其中包年包月和按量付费两种主流模式。对于准备在阿里云上部署应用的用户来说,选择合适的收费模式至关重要,因为它直接关系到成本控制和资源使用的灵活性。本文将对这两种收费模式做一个对比,以供参考和选择。
780 14
|
12月前
|
监控 安全 物联网
智能家居安全:保护您的家庭免受网络威胁##
随着物联网 (IoT) 技术的迅猛发展,越来越多的家庭设备连接到互联网,带来便利的同时,也增加了网络安全风险。本文将深入探讨智能家居设备的常见安全漏洞、潜在威胁以及防护措施,帮助您了解如何保护家庭免受网络威胁。 ##
|
编译器 C++
【C++11保姆级教程】final和override
【C++11保姆级教程】final和override
409 0
|
设计模式 程序员 编译器
C++中的纯虚类(Pure Virtual Classes)
C++中的纯虚类(Pure Virtual Classes)
1196 1
|
10月前
|
前端开发 JavaScript 安全
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第7天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤。包括项目准备、安装 `javascript-obfuscator`、配置 Vite 构建以应用混淆,以及最终构建项目进行混淆。通过这些步骤,可以有效提升前端代码的安全性,防止被他人轻易分析和盗用。
1949 0
|
人工智能 编解码 API
通义万相AIGC技术测评报告
**摘要:** 通义万相是阿里云的AI绘画模型,提供清晰的部署指南和易用的API,适合新手。资源部署耗时约10分钟,API响应快,支持多种风格图片生成,适用于广告、媒体等领域。产品性价比高,功能包括文本到图像转换等,但仍有改进空间,如增加服装纹理选项、互动功能和更多API接口。建议完善功能、加强推广和降低成本以吸引更多用户。[链接](https://developer.aliyun.com/topic/tongyi-wanxiang?spm=a2c6h.27063436.J_6978680750.5.3a774f461hv8qD)
923 6
|
Python
将Django项目从本地上传至宝塔服务器(踩坑记录)
将Django项目从本地上传至宝塔服务器(踩坑记录)
151 2
|
设计模式 算法 程序员
【C++】大气、正规的编程习惯:C++学习路径与注意事项
【C++】大气、正规的编程习惯:C++学习路径与注意事项
200 0
|
存储 缓存 开发框架
Flutter的网络请求:使用Dart进行HTTP请求的技术详解
【4月更文挑战第26天】了解Flutter网络请求,本文详述使用Dart进行HTTP请求