*HDU 1086 计算几何

You can Solve a Geometry Problem too

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10259    Accepted Submission(s): 5074

Problem Description

Many
geometry(几何)problems were designed in the ACM/ICPC. And now, I also
prepare a geometry problem for this final exam. According to the
experience of many ACMers, geometry problems are always much trouble,
but this problem is very easy, after all we are now attending an exam,
not a contest :)
Give you N (1<=N<=100) segments(线段), please
output the number of all intersections(交点). You should count repeatedly
if M (M>2) segments intersect at the same point.

Note:
You can assume that two segments would not intersect at more than one point.

Input

Input
contains multiple test cases. Each test case contains a integer N
(1=N<=100) in a line first, and then N lines follow. Each line
describes one segment with four float values x1, y1, x2, y2 which are
coordinates of the segment’s ending.
A test case starting with 0 terminates the input and this test case is not to be processed.

Output

For each case, print the number of intersections, and one line one case.

Sample Input

2

0.00 0.00 1.00 1.00

0.00 1.00 1.00 0.00

3

0.00 0.00 1.00 1.00

0.00 1.00 1.00 0.000

0.00 0.00 1.00 0.00
0

Sample Output

1

3

Author

lcy

题意:

给出n条线段问有几个交点。

这道题的主要解题思路如下:

第1 步:快速排斥试验,如果分别以P1P2 ,P3P4 为对角线做矩形,而这两个矩形不相交,则这两条线段肯定不相交,如下左图;即使两个矩形相交,这两条线段也不一定相交,如下右图,这时再用第2 步判断;

表示成语句,即两个矩形相交当且仅当下列式子为真:

(max(x1,x2)≥min(x3,x4))&& (max(x3,x4)≥min(x1,x2)) &&(max(y1,y2)≥min(y3,y4))&&(max(y3,y4)≥min(y1,y2))

两个矩形相交必须在两个方向上都相交,式子的前半部分判断在x 方向上是否相交,后半部分判断在y 方向上是否相交。

第2 步:确定每条线段是否“跨立”另一条线段所在的直线。

跨立:如果点P1 处于直线P3P4的一边,而P2处于该直线的另一边,则我们说线段p1p2跨立直线P3P4,如果P1 或P2 在直线P3P4 上,也算跨立。

两条线段相交当且仅当它们能够通过第1 步的快速排斥试验,并且每一条线段都跨立另一条线段所在的直线。

具体第2 步的实现,只要用叉积去做就可以了,即只要判断矢量p1p3和p1p4是否在p1p2的两边相对的位置上,如果这样,则线段p1p2跨立直线P3P4。也即检查叉积(P3-P1)×(P2-P1)与(P4-P1)×(P2-P1)的符号是否相同,相同则不跨立,线段也就不相交,否则相交。

当然也有一些特殊情况需要处理,如任何一个叉积为0,则P3 或P4 在直线P1P2 上,又因为通过了快速排斥试验,所以下图左边的情况是不可能出现的,只会出现右边的两种情况。当然,还会出现一条或两条线段的长度为0,如果两条线段的长度都是0,则只要通过快速排斥试验就能确定;如果仅有一条线段的长度为0,如p3p4的长度为0,则线段相交当且仅当叉积(P3-P1)×(P2-P1)。

有关于叉积的概念:

矢量的矢量积(叉乘、叉积)

① 矢量积的一般含义:两个矢量a 和b 的矢量积是一个矢量,记作a×b,其模等于由a 和b作成的平行四边形的面积,方向与平行四边形所在平面垂直,当站在这个方向观察时,a 逆时针转过一个小于π的角到达b 的方向。这个方向也可以用物理上的右手螺旋定则判断:右手四指弯向由A 转到B 的方向(转过的角小于π),拇指指向的就是矢量积的方向。如下图(左)。

        

② 我们给出叉积的等价而更有用的定义,把叉积定义为一个矩阵的行列式:

如上右图,如果  p1 × p2 为正数,则相对原点(0,0)来说, p1 p 2 的顺时针方向; 如果p 1  × p2为负数,则p 1 在p 2 的逆时针方向。如果p 1× p =0,则p 1和p 2 模相等且共线,方向相同或相反。

③ 给定两个矢量:P0P1和P0P2,对它们的公共端点P0来说,判断P0P1是否在P0P2的顺时针方向。

方法:如上图,把0 作为原点,得出向量P1’=P1-P0 和P2’=P2-P0,因此,这两个向量的叉积为: 如果该叉积为正,则P0P1在P0P2的顺时针方向,如果为负,则P0P1在P0P2的逆时针方向。如果等于0,则P0,P1,P2三点共线。

④ 讨论另一个重要问题:确定连续线段是向左转还是向右转,如下图,即两条连续线段P0P1

P1P2在点P1 是向左转还是向右转。也即∠P1P0P2的转向。

方法:叉积,同上。

这道题还要注意一点:

还有一些情况要考虑:

就这样!   (上面说的是异号就对了,即两条线段要相互判断另一条的端点在自己的两侧)。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 double nodx1[102],nody1[102],nodx2[102],nody2[102];
 7 int n;
 8 int main()
 9 {
10     while(scanf("%d",&n)&&n)
11     {
12         for(int i=0;i<n;i++)
13         scanf("%lf%lf%lf%lf",&nodx1[i],&nody1[i],&nodx2[i],&nody2[i]);
14         double x1,y1,x2,y2;
15         int ans=0;
16         for(int i=0;i<n-1;i++)
17         for(int j=i+1;j<n;j++)
18         {
19             if(!((min(nodx1[i],nodx2[i])<=max(nodx1[j],nodx2[j]))
20                  &&(max(nody1[i],nody2[i])>=min(nody1[j],nody2[j]))
21                  &&(min(nodx1[j],nodx2[j])<=max(nodx1[i],nodx2[i]))
22                  &&(max(nody1[j],nody2[j])>=min(nody1[i],nody2[i]))))
23                  continue;                        //测试数据较水,没有这个判断也能过。
24             x1=nodx2[i]-nodx1[i];y1=nody2[i]-nody1[i];
25             x2=nodx2[j]-nodx1[i];y2=nody2[j]-nody1[i];
26             double tem1=x2*y1-x1*y2;
27             x2=nodx1[j]-nodx1[i];y2=nody1[j]-nody1[i];
28             double tem2=x2*y1-x1*y2;
29             x1=nodx2[j]-nodx1[j];y1=nody2[j]-nody1[j];
30             x2=nodx2[i]-nodx1[j];y2=nody2[i]-nody1[j];
31             double tem3=x2*y1-x1*y2;
32             x2=nodx1[i]-nodx1[j];y2=nody1[i]-nody1[j];
33             double tem4=x2*y1-x1*y2;
34             if(tem1*tem2<=0&&tem3*tem4<=0) ans++;
35         }
36         printf("%d\n",ans);
37     }
38     return 0;
39 }
时间: 2024-11-05 18:50:09

*HDU 1086 计算几何的相关文章

hdu 1086(计算几何入门题——计算线段交点个数)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086 You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7167    Accepted Submission(s): 3480 Problem Description Ma

HDU 1086 You can Solve a Geometry Problem too(判断线段相交)

题目地址:HDU 1086 就这么一道仅仅判断线段相交的题目写了2k多B的代码..是不是有点浪费...但是我觉得似乎哪里也优化不了了.... 判断线段相交就是利用的叉积.假如现在两条线段分别是L1和L2,先求L1和L2两个端点与L1的某个端点的向量的叉积,如果这两个的叉积的乘积小于0的话,说明L1在是在L2两个端点之间的,但此时并不保证一定相交.此时需要用同样的方法去判断L2是否在L1的两个端点之间,如果L2也在L1的两个端点之间的话,那就足以说明L1与L2相交.但是这题还需要判断是否端点也相交

HDU 1086:You can Solve a Geometry Problem too

You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6997    Accepted Submission(s): 3385 Problem Description Many geometry(几何)problems were designed in the ACM/

hdu 1086 You can Solve a Geometry Problem too (几何)

You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6932    Accepted Submission(s): 3350 Problem Description Many geometry(几何)problems were designed in the ACM/I

HDU 1086 [You can Solve a Geometry Problem too] 计算几何

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086 题目大意:给N条线段,问这些线段共有多少交点,多线交于一点要重复计算. 关键思想:叉乘可根据右手法则判断正负,相互跨越或者一条线段端点在另一条线段上则交点数+1. 代码如下: #include <iostream> using namespace std; const int MAXN=110; struct point{ double x,y; }; struct line{ point

hdu 1616 计算几何 凸包

题意是一个世界有许多个国家,每个国家有N个建筑,包括一个发电站和N-1个用电建筑,所有建筑围成的凸包就是这个国家的面积.一枚导弹如果在一个国家之内爆炸则可以使这个国家停电. step 1:求出每个国家的凸包(我用水平排序就是各种坑,改叉乘排序才过,主要是后面求面积的时候需要这个叉乘排序的信息). step 2:判断每枚导弹是否在这个国家的范围之内. step 3:求出所有停电的国家的面积. 就是计算几何的综合模拟水题,坑点就是要小心(QAQ||写计算几何的题目都是要小心). 传送门:http:/

hdu 1086 You can Solve a Geometry Problem too(求线段相交点个数 模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1086 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593830943

hdu 3320 计算几何(三维图形几何变换)

openGL Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 170    Accepted Submission(s): 77 Problem Description Jiaoshou selected a course about “openGL” this semester. He was quite interested in m

HDU 5784 (计算几何)

Problem How Many Triangles (HDU 5784) 题目大意 给定平面上的n个点(n<2000),询问可以组成多少个锐角三角形. 解题分析 直接统计锐角三角形较困难,考虑问题的反面,统计直角三角形.钝角三角形.平角三角形(暂时这么叫吧QAQ). 首先枚举三角形的一个端点A,对其他点进行象限为第一关键字,极角为第二关键字排序. 然后使用三个指针,进行O(n)的扫描. 具体做法为用 i 指针指向三角形的第二个端点B.我们可以假想通过平移和旋转,把A点置于平面直角坐标系的原点,