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. }


相关文章
|
算法
ACM刷题之路(五)最短路 Dijkstra POJ2387
ACM刷题之路(五)最短路 Dijkstra POJ2387
ACM刷题之路(十八)二分 2019暑期集训 POJ 3579 Median
ACM刷题之路(十八)二分 2019暑期集训 POJ 3579 Median
ACM刷题之路(十五) 分治法 + 找规律 ZOJ4085
ACM刷题之路(十五) 分治法 + 找规律 ZOJ4085
105 0
ACM刷题之路(二十四)HDU 2844 多重背包转换 Coins
ACM刷题之路(二十四)HDU 2844 多重背包转换 Coins
103 0
|
算法 Java Python
ACM 选手图解 LeetCode 翻转二叉树
ACM 选手图解 LeetCode 翻转二叉树
ACM 选手图解 LeetCode 翻转二叉树
|
存储 Java Python
ACM 选手图解 LeetCode 找树左下角的值
ACM 选手图解 LeetCode 找树左下角的值
ACM 选手图解 LeetCode 找树左下角的值
|
Java Python
ACM 选手图解 LeetCode 二叉树的最小深度
ACM 选手图解 LeetCode 二叉树的最小深度
ACM 选手图解 LeetCode 二叉树的最小深度
|
机器学习/深度学习 算法 Java
ACM 选手图解 LeetCode 模拟法解决螺旋矩阵Ⅱ
给定正整数 n,生成一个包含 1 ~ n² 所有元素,且元素按顺时针螺旋排列的 n * n 正方形矩阵 matrix。
ACM 选手图解 LeetCode 模拟法解决螺旋矩阵Ⅱ
[小玄的刷题日记]《LeetCode零基础指南》转置矩阵
[小玄的刷题日记]《LeetCode零基础指南》转置矩阵
132 0
[小玄的刷题日记]《LeetCode零基础指南》转置矩阵
|
存储 算法
笔试算法模拟题精解之“矩阵最小路径和”
本文介绍了暴力递归求解和动态规划求解两种方法来解答这道题目。