promise me a medal(线段相交 && 求交点)

描述

  you all know that creat2012 will go to a regional. and i want you all pray for us. thx.

  for this problem, you need judge if two segments is intersection(相交的). if intersect(相交), print yes and the point. else print no.

  easy ? ac it.

输入
T <= 100 cases
8 real numbers (double)
promise two segments is no coincidence.
输出
no
or yes and two real number (one decimal)
样例输入
2
0 0 2 2 1 0 3 2
0 0 2 2 0 2 2 0
样例输出
no
yes 1.0 1.0

 思路:PS 需要特殊情况  共线&&无交点  共线有交点 

 步骤:

(1),需一个四个大小的数组再次表示四个点坐标 对该数组排序 如果中间两个点坐标相等则 两线段相交。

(2),若不等则进行快速排斥实验 排除掉   共线无交点 

(3),根据叉乘运算 确定线段是否相交, 若相交 则利用定比分点来求交点坐标


PS:定比分点:一条直线po,p(x1,y1),o(x2,y2),m是po两点中的一点 若pm/mo=k则m.x=(x1+kx2)/(1+k)   m.y=(y1+ky2)/(1+k);

我的思路里 最后一步(通过了快速排斥实验见 转载日志)用到定比分点公式 即 四点能组成四边形,以st1 ed1线段为公共边的两个三角形 st1ed1st2  和三角形 st1 ed1 ed2

叉乘可知三角形的面积 面积比则为高的比 两个小直角三角形相似 大三角形高的比 即为小直角三角形斜边的比即:st2 O/ed2O即定比分点的k值 则可求O点坐标。

代码:

<pre name="code" class="cpp">#include<iostream>
#include<stdio.h>
#include <iomanip>
#include<algorithm>
#include<math.h>
using namespace std;

struct node
{
    double x,y;
} st1,ed1,st2,ed2,s[4];
double area(node ss1,node ee1,node ss2)
{
    //return ss1.x*ee1.y-ss1.y*ee1.x;
    return (ss1.x-ee1.x)*(ss1.y-ss2.y)-(ss1.x-ss2.x)*(ss1.y-ee1.y);
}
int cmp(node a,node b)
{
    if(a.x>b.x)
        return a.x<b.x;
    if(a.x==b.x)
        return a.y<b.y;
}
int main()
{
    int t,i,j;
    cin>>t;
    while(t--)
    {
        cin>>st1.x>>st1.y>>ed1.x>>ed1.y>>st2.x>>st2.y>>ed2.x>>ed2.y;
        s[0]=st1;
        s[1]=ed1;
        s[2]=st2;
        s[3]=ed2;
        double s1=area(st1,ed1,st2);
        double s2=area(st1,ed1,ed2);
        double s3=area(st2,ed2,st1);
        double s4=area(st2,ed2,ed1);
        cout.setf(ios::fixed);
        cout.precision(1);
        sort(s,s+4,cmp);
        if(s[1].x==s[2].x&&s[1].y==s[2].y)
            cout<<"yes "<<s[2].x<<" "<<s[2].y<<endl;
        else
        {
            if(!(min(st1.x,ed1.x)<=max(st2.x,ed2.x) && min(st1.y,ed1.y)<=max(st2.y,ed2.y)&&
                    min(st2.x,ed2.x)<=max(st1.x,ed1.x) && min(st2.y,ed2.y)<=max(st1.y,ed1.y)))
                cout<<"no"<<endl;
            else
            {
                if(s1*s2<=0&&s3*s4<=0)
                {
                    if(s1==0)
                        cout<<"yes "<<st2.x<<" "<<st2.y<<endl;
                    else if(s2==0)
                        cout<<"yes "<<ed2.x<<" "<<ed2.y<<endl;
                    else if(s3==0)
                        cout<<"yes "<<st1.x<<" "<<st1.y<<endl;
                    else if(s4==0)
                        cout<<"yes "<<ed1.x<<" "<<ed1.y<<endl;
                    if(s1!=0&&s2!=0&&s3!=0&&s4!=0)
                    {
                        double ss=fabs(1.0*s1/s2);
                        //cout<<ss<<endl;
                        node ans;
                        ans.x=(st2.x+ss*ed2.x)/(1+ss);
                        ans.y=(st2.y+ss*ed2.y)/(1+ss);
                        cout<<"yes "<<ans.x<<" "<<ans.y<<endl;
                    }
                }
                else
                    cout<<"no"<<endl;
            }
        }
    }
    return 0;
}
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值