模板--判断两线段是否相交
2016-04-16 16:16
316 查看
题目链接:
POJ 1127 Jack Straws
题意:
已知n条木棍的起点和终点坐标,问第i条木棍和第j条木棍是否相连?当两条木棍之间有公共点时,就认为他们时相连的。通过相连的木棍
间接的连在一起的两根木棍也认为时相连的。
分析:
木棍就是二维平面上的线段,只要能判断线段是否相交,那么建图后可以通过Floyd算法或者并查集进行连接性判断。
如何判断两条线段是否相交呢?首先会想到计算两条直线的交点,然后判断焦点是否在线段上。那么两条直线的交点如何求得呢?虽然可以把直线表示成方程,通过建立方程组求解。但在几何问题中,运用向量的内积和外积进行计算是非常方便的。
对于二维向量p1=(x1,y1)和p2=(x2,y2),我们定义
内积p1⋅p2=x1∗x2+y1∗y2,
外积p1Xp2=x1∗y2−x2∗y1.
要判断点q是否在线段p1−p2上,只要
先利用外积根据是否有
(p1−q)X(p2−q)==0来判断点q是否在直线p1−p2上,
再利用内积根据是否有
(p1−q)⋅(p2−q)<=0来判断点q是否落在p1−p2之间。
而要求两直线的交点,通过变量t将直线p1−p2上的点表示为p1+t(p2−p1),交点又在直线q1−q2上,所以有:
于是可以利用下式求得t的值:
但是使用这个方法还要注意边界情况。也就是平行的线段也可能有公共点。这是我们可以选择通过检查端点是否在另一条线段上来判断。
以上摘自《挑战程序设计竞赛》
POJ 1127 Jack Straws
题意:
已知n条木棍的起点和终点坐标,问第i条木棍和第j条木棍是否相连?当两条木棍之间有公共点时,就认为他们时相连的。通过相连的木棍
间接的连在一起的两根木棍也认为时相连的。
分析:
木棍就是二维平面上的线段,只要能判断线段是否相交,那么建图后可以通过Floyd算法或者并查集进行连接性判断。
如何判断两条线段是否相交呢?首先会想到计算两条直线的交点,然后判断焦点是否在线段上。那么两条直线的交点如何求得呢?虽然可以把直线表示成方程,通过建立方程组求解。但在几何问题中,运用向量的内积和外积进行计算是非常方便的。
对于二维向量p1=(x1,y1)和p2=(x2,y2),我们定义
内积p1⋅p2=x1∗x2+y1∗y2,
外积p1Xp2=x1∗y2−x2∗y1.
要判断点q是否在线段p1−p2上,只要
先利用外积根据是否有
(p1−q)X(p2−q)==0来判断点q是否在直线p1−p2上,
再利用内积根据是否有
(p1−q)⋅(p2−q)<=0来判断点q是否落在p1−p2之间。
而要求两直线的交点,通过变量t将直线p1−p2上的点表示为p1+t(p2−p1),交点又在直线q1−q2上,所以有:
(q2-q1)X(p1+(p2-p1)-q1)==0
于是可以利用下式求得t的值:
p1+(p2-p1)*((q2-q1)X(q1-p1)/(q2-q1)X(p2-p1)).
但是使用这个方法还要注意边界情况。也就是平行的线段也可能有公共点。这是我们可以选择通过检查端点是否在另一条线段上来判断。
以上摘自《挑战程序设计竞赛》
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <iostream> #include <climits> #include <string> using namespace std; double EPS=1e-10; const int MAX_N=20; int n; bool connected[MAX_N][MAX_N]; int pre[MAX_N]; //考虑误差的加法运算 double add(double a,double b) { if(abs(a+b)<EPS*(abs(a)+abs(b))) return 0; return a+b; } struct Point { double x,y; Point() {} Point(double x,double y):x(x),y(y){ } Point operator + (const Point& rhs) const { return Point(add(x,rhs.x),add(y,rhs.y)); } Point operator - (const Point& rhs) const { return Point(add(x,-rhs.x),add(y,-rhs.y)); } Point operator * (const double d) const { return Point(x*d,y*d); } double dot(const Point& rhs) const { //内积 return add(x*rhs.x,y*rhs.y); } double cross(const Point& rhs) const { //外积 return add(x*rhs.y,-y*rhs.x); } }st[MAX_N],ed[MAX_N];//st[i],ed[i]分别是第i条线段的起点和终点 //判断点q是否在线段p1-p2上 bool on_seg(Point p1,Point p2,Point q) { return (p1-q).cross(p2-q)==0&&(p1-q).dot(p2-q)<=0; } //计算直线p1-p2与直线q1-q2的交点 Point intersection(Point p1,Point p2,Point q1,Point q2) { return p1+(p2-p1)*((q2-q1).cross(q1-p1)/(q2-q1).cross(p2-p1)); } //Floyd_Warshall算法判断任意两条木棍是否相连 void Floyd_Warshall() { for(int k=0;k<n;k++){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ connected[i][j] |= connected[i][k]&&connected[k][j]; } } } } int find(int x) { return pre[x]==x?x:pre[x]=find(pre[x]); } //并查集判断任意两条木棍是否相连 void UnionFindSet() { for(int i=0;i<n;i++) pre[i]=i; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(connected[i][j]&&find(i)!=find(j)){ pre[j]=i; } } } } void solve() { for(int i=0;i<n;i++){ connected[i][i]=true; for(int j=0;j<i;j++){//判断木棍i和j是否有公共点 if((st[i]-ed[i]).cross(st[j]-ed[j])==0){//木棍平行时 connected[i][j]=connected[j][i]=on_seg(st[i],ed[i],st[j]) || on_seg(st[i],ed[i],ed[j]) || on_seg(st[j],ed[j],st[i]) || on_seg(st[j],ed[j],ed[i]); } else {// 不平行时 Point inter=intersection(st[i],ed[i],st[j],ed[j]); connected[i][j]=connected[j][i]=on_seg(st[i],ed[i],inter)&&on_seg(st[j],ed[j],inter); } } } Floyd_Warshall(); UnionFindSet(); } int main() { while(~scanf("%d",&n)&&n){ for(int i=0;i<n;i++){ scanf("%lf%lf%lf%lf",&st[i].x,&st[i].y,&ed[i].x,&ed[i].y); } solve(); int a,b; while(~scanf("%d%d",&a,&b)&&(a||b)){ //if(connected[a-1][b-1]) printf("CONNECTED\n"); if(find(a-1)==find(b-1)) printf("CONNECTED\n"); else printf("NOT CONNECTED\n"); } } return 0; }
相关文章推荐
- 设计模式之行为型模式 - 调用行为的传递问题
- [div+css]晒晒最新制作专题推广页模板
- 2008大学生入党申请书 模板
- IMAIL多语言模板两套Outlook&Gmail模板下载
- 在PHP中使用模板的方法
- 深入解析php模板技术原理【一】
- Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
- 在ASP中不用模板生成HTML静态页直接生成.html页面
- 基于HTML模板和JSON数据的JavaScript交互(移动端)
- C#模板方法模式(Template Method Pattern)实例教程
- javascript文本模板用法实例
- 关于Asp代码与页面的分离模板技术第1/3页
- php模板原理讲解
- 需要使用php模板的朋友必看的很多个顶级PHP模板引擎比较分析
- DataGrid 动态添加模板列 实现代码
- 详解java模板和回调机制
- C++模板之特化与偏特化详解
- vs.net2008添加模板方法
- ThinkPHP模板判断输出Empty标签用法详解
- ThinkPHP模板范围判断输出In标签与Range标签用法详解