• 判断两线段相交


    点乘

      一个向量在另一个向量上的投影长度,标量,用于判断角度

    叉乘

      垂直两向量的平面,右手定则,矢量,用于判断方向

    参考博客:点击进入

    (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。

    例题:51nod1264

     1 #include<iostream>
     2 using namespace std;
     3 
     4 struct Point
     5 {
     6     double x, y;
     7 } dot[4];
     8 
     9 double cross(Point a, Point b, Point c)
    10 {
    11     double nx1, ny1, nx2, ny2;
    12     nx1 = b.x - a.x;
    13     ny1 = b.y - a.y;
    14     nx2 = c.x - b.x;
    15     ny2 = c.y - b.y;
    16     return nx1 * ny2 - ny1 * nx2;
    17 }
    18 
    19 int main()
    20 {
    21     int t;
    22     cin >> t;
    23     while(t--)
    24     {
    25         for(int i = 0; i < 4; i++)
    26             cin >> dot[i].x >> dot[i].y;
    27         double s1, s2, s3, s4;
    28         //这里的三点顺序需要注意,可由叉乘相关性质推导出
    29         s1 = cross(dot[0], dot[2], dot[3]);
    30         s2 = cross(dot[3], dot[2], dot[1]);
    31         s3 = cross(dot[2], dot[0], dot[1]);
    32         s4 = cross(dot[1], dot[0], dot[3]);
    33         if(s1 * s2 >= 0 && s3 * s4 >= 0)
    34             cout << "YES" << endl;
    35         else
    36             cout << "NO" << endl;
    37     }
    38     return 0;
    39 }

    关于上面的顺序问题,画个图加深一下理解

    例题:hdu1086

     1 #include<iostream>
     2 using namespace std;
     3 
     4 struct Point
     5 {
     6     double x, y;
     7 } dot[220];
     8 
     9 struct Seg
    10 {
    11     Point fir, sec;
    12 } Seg[110];
    13 
    14 double cross(Point a, Point b, Point c)
    15 {
    16     double nx1, ny1, nx2, ny2;
    17     nx1 = b.x - a.x;
    18     ny1 = b.y - a.y;
    19     nx2 = c.x - b.x;
    20     ny2 = c.y - b.y;
    21     return nx1 * ny2 - ny1 * nx2;
    22 }
    23 
    24 int is_cross(Point a, Point b, Point c, Point d)
    25 {
    26     double s1, s2, s3, s4;
    27     s1 = cross(a, c, d);
    28     s2 = cross(d, c, b);
    29     s3 = cross(c, a, b);
    30     s4 = cross(b, a, d);
    31     if(s1 * s2 >= 0 && s3 * s4 >= 0)
    32         return 1;
    33     return 0;
    34 }
    35 int main()
    36 {
    37     int n;
    38     while(cin >> n && n)
    39     {
    40         int ans = 0;
    41         for(int i = 0; i < n; i++)
    42         {
    43             cin >> Seg[i].fir.x >> Seg[i].fir.y >> Seg[i].sec.x >> Seg[i].sec.y;
    44         }
    45         for(int i = 0; i < n; i++)
    46         {
    47             for(int j = i + 1; j < n; j++)
    48             {
    49                 if(is_cross(Seg[i].fir, Seg[i].sec, Seg[j].fir, Seg[j].sec))
    50                     ans++;
    51             }
    52         }
    53         cout << ans << endl;
    54     }
    55     return 0;
    56 }

     体会:

      计算几何题需要对几何知识有一定的熟悉,有时一行公式代码可能要推导一会儿时间,所以个人感觉这类题模板和公式总结很重要,慢慢积累吧~

  • 相关阅读:
    redis 基本类型命令
    吴寿仁 学术
    吴寿仁:上海科技成果转化40年
    从“四技”服务的收益中提取奖酬金是否不受当年本单位工资总额限制、不纳入本单位工资
    高校科技成果转化为什么就这样的难
    高校成果转换
    中华人民共和国 促进科技成果转化法
    上海市促进科技成果转化条例
    项目管理
    欧几里得方法计算最大公约数Python版本
  • 原文地址:https://www.cnblogs.com/friend-A/p/10446626.html
Copyright © 2020-2023  润新知