ACM复习(25)8630 连线游戏

Description
在一张纸上,画着很多个点,小明和小强用这张纸玩游戏,游戏规则如下
1.每人轮流选两个点,然后两点间画一条线段
2.选过的点,不能再选
3.谁首先产生交点,谁就输
4.有人输了,或者剩下的点少于2 个,游戏结束
现在,你作为这个游戏的裁判,需要编写一个程序,判断平面上的两条线段是否相交。

输入格式
第一行输入正整数t,t>64,表示case 个数,后面的t行,每行是8 个整数,x1,y1,x2,y2,x3,y3,x4,y4
坐标范围是[0,32767]
point(x1,y1) point(x2,y2) point(x3,y3) point(x4,y4)互不重合
线段a(point(x1,y1),point(x2,y2))
线段b(point(x3,y3),point(x4,y4))

输出格式
若线段a,b 存在交点输出y,否则输出n。

输入样例
4
0 0 0 1 0 2 0 3
0 0 0 2 0 1 0 3
0 0 2 2 0 2 2 0
0 0 1 1 0 2 2 0

输出样例
n
y
y
y


解题思路

求出一条线段所在直线的直线方程,判断另一线段的端点与直线的相对位置(同侧,异侧还是直线上),
然后对另一条线段同样处理

求直线方程:
已知两点时,直线AX+BY+C=0的一般式方程就是:
A = Y2 - Y1
B = X1 - X2
C = X2*Y1 - X1*Y2

判断点与直线的相对位置:
设点P(x, y),将P代入直线方程得
z = Ax + By + C
z = 0(在直线上)z > 0 or z < 0(在其中一侧)

特殊情况的处理例如:

  1. 线段穿越直线但不穿越线段
  2. 线段同线但不相交

注意:
判断相对位置是否异号不要用z1 * z2 < 0来判断,因为计算过程可能溢出

#include<stdio.h>
#include<math.h>
double dis(int x, int y, int a, int b);
int interset(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
int main()
{
    int t, x1, y1, x2, y2, x3, y3, x4, y4, flag;
    scanf("%d", &t);
    while(t --)
    {
        flag = 0;
        scanf("%d %d %d %d %d %d %d %d", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
        flag += interset(x1, y1, x2, y2, x3, y3, x4, y4);
        flag += interset(x3, y3, x4, y4, x1, y1, x2, y2);
        // 线段都穿过对应直线或其中一线段的至少一个端点在另一线段上
        if(flag >= 2)
            printf("y\n");
        else
            printf("n\n");
    }
    return 0;
}
// 直线(x1, y1) (x2, y2) 线段 (x3, y3), (x4, y4)
int interset(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)
{
    int a, b, c, t1, t2, flag;
    a = y2 - y1;
    b = x1 - x2;
    c = x2 * y1 - x1 * y2;
    // 相对位置
    t1 = a * x3 + b * y3 + c;
    t2 = a * x4 + b * y4 + c;
    // 同号
    if((t1 < 0 && t2 < 0) || (t1 > 0 && t2 > 0))
        flag = 0;
    // 至少一个端点在直线上
    else if(t1 == 0 || t2 == 0)
    {
        其中一个端点在线段上
        if(fabs(dis(x3, y3, x1, y1) + dis(x3, y3, x2, y2) - dis(x1, y1, x2, y2)) < 0.00001)
            flag = 2;
        或者另一端点在线段上
        else if(fabs(dis(x4, y4, x1, y1) + dis(x4, y4, x2, y2) - dis(x1, y1, x2, y2)) < 0.00001)
            flag = 2;
        else 
            flag = 0;
    }
    // 异号(线段穿过直线但不一定穿过线段)
    else
        flag = 1;
    return flag;
}
double dis(int x, int y, int a, int b)
{
    return sqrt((x - a) * (x - a) + (y - b) * (y - b));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值