hdu 1086 判断两线段是否相交 (线段和直接是否相交)
几何题做的很少,以至于一个很简单的题目写了很久
若是判断直线和线段是否有交点,把on_segment去掉就可以了
我们分两步确定两条线段是否相交:
(1)快速排斥试验
设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交。
(2)跨立试验
如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所示:
在相同的原理下,对此算法的具体的实现细节可能会与此有所不同,除了这种过程外,大家也可以参考《算法导论》上的实现。
关于计算几何算法概述网站 http://dev.gameres.com/Program/Abstract/Geometry.htm 一个挺好的网站
#include<stdio.h> struct point { double x,y; }; double direction( point p1,point p2,point p ) { return ( p1.x -p.x )*( p2.y-p.y) - ( p2.x -p.x )*( p1.y-p.y) ; } int on_segment( point p1,point p2 ,point p ) { double max=p1.x > p2.x ? p1.x : p2.x ; double min =p1.x < p2.x ? p1.x : p2.x ; if( p.x >=min && p.x <=max ) return 1; else return 0; } int segments_intersert( point p1,point p2,point p3,point p4 ) { double d1,d2,d3,d4; d1 = direction ( p1,p2,p3 ); d2 = direction ( p1,p2,p4 ); d3 = direction ( p3,p4,p1 ); d4 = direction ( p3,p4,p2 ); if( d1*d2<0 && d3*d4<0 ) return 1; else if( d1==0 && on_segment( p1,p2,p3 ) ) return 1; else if( d2==0 && on_segment( p1,p2,p4 ) ) return 1; else if( d3==0 && on_segment( p3,p4,p1 ) ) return 1; else if( d4==0 && on_segment( p3,p4,p2 ) ) return 1; return 0; } int main() { int n,i,j,num; point begin[105],end[105]; while( scanf("%d",&n) && n!=0 ) { num=0; for( i=0;i<n;i++) { scanf("%lf %lf %lf %lf",&begin[i].x ,&begin[i].y ,&end[i].x ,&end[i].y ); } for( i=0;i<n;i++) for(j=i+1;j<n;j++) { if( segments_intersert( begin[i],end[i],begin[j],end[j] ) ) num++; } printf("%d\n",num); } return 0; }
计算几何算法概览
计算几何算法概览
计算几何算法概览
计算几何算法概览