HDOJ 1086 You can Solve a Geometry Problem too
题目
分类
几何 判断线段交叉
题意
给出 N 个点
求叫点数
题解
逐个扫描 线段是否相交
主要是判断相交的算法
首先看快速排斥实验
快速排斥实验是一种 快速判断线段是否相交的实验
思想 是 判断以线段做对角线的矩形是否相交 来判断线段是否相交
如上图 可以说明 快速排斥实验不相交的线段一定不相交 但是 相交的的不一定线段相交如中间图
P1 = (x1, y1), P2 = (x2, y2), Q1 = (x3, y3), Q2 = (x4, y4)
算法描述 如 最右方图 可见 矩形不想交 意味着 min(x1,x2) >= max(x3,x4)(P1P2 在 Q1Q2上面) 或者 max(x1,x2) <= min(x3,x4)(P1P2 在 Q1Q2下面) 或者 min(y1,y2) >= max(y3,y4)(P1P2 在 Q1Q2左面)或者 max(y1,y2) <= min(y3,y4)(P1P2 在 Q1Q2下面)
意义 快速判断 只能确定是否不相交由于 快速排斥实验 不能确定是否相交 所以 引出一个能确定的算法
跨立实验
判断直线是否 可以被另一个相交
有 下式 (P1 - Q1)*(Q2 - Q1) * (Q2 - Q1)* (P2 - Q1) > 0 ,当 (P1 - Q1) * (Q2 - Q1) = 0 表示共线 所以通过跨立实验 的 线段 相交条件为 (P1 - Q1)*(Q2 - Q1) * (Q2 - Q1) * (P2 - Q1) >= 0
技巧
由于 先进行 快速排斥实验 后 排斥实验
也已用 && 连接&& 短路
例如 A && B
若 A 为假 则 B 不被执行
代码
#include <iostream>
#define N 101
using namespace std;
struct Point
{
double x;
double y;
friend bool operator==(const Point & p,const Point & q)
{
return (p.x == q.x && p.y == q.y);
}
friend bool operator<(const Point & p,const Point & q)
{
return p.x < q.x;
}
};
struct Line
{
Point p;
Point q;
};
Line ln[N];
bool IsCross(Line u,Line v);
int main()
{
int mn,ans;
Point cp;
while(cin >> mn && mn)
{
ans = 0;
for(int i = 1;i <= mn;i++)
{
cin >> ln[i].p.x >> ln[i].p.y >> ln[i].q.x >> ln[i].q.y;
}
for(int i = 1;i < mn;i++)
for(int j = i+1;j <= mn;j++)
if(IsCross(ln[i],ln[j]))
ans++;
cout << ans << endl;
}
return 0;
}
float Mul(Point a,Point b,Point c)
{
return (a.x - c.x)*(b.y - c.y)-(b.x - c.x)*(a.y - c.y);
}
bool IsCross(Line u,Line v)
{
return (max(u.p.x,u.q.x) >= min(v.p.x,v.q.x)) &&
(max(v.p.x,v.q.x) >= min(u.p.x,u.q.x)) &&
(max(u.p.y,u.q.y) >= min(v.p.y,v.q.y)) &&
(max(v.p.y,v.q.y) >= min(u.p.y,u.q.y)) &&
(Mul(v.p,u.q,u.p) * Mul(u.q,v.q,u.p) >= 0) &&
(Mul(u.p,v.q,v.p) * Mul(v.q,u.q,v.p) >= 0);
}