HDU 3803 gxx‘s Problem

gxx’s Problem - http://acm.hdu.edu.cn/showproblem.php?pid=3803

模板

https://blog.csdn.net/clasky/article/details/9990235

https://blog.csdn.net/weixin_44146025/article/details/97272311

分析

根据面积的比例计算交点
在这里插入图片描述

代码

#include <iostream>
using namespace std;
#define LL long long
// 符号函数
int sign(const LL &v){
    if (v > 0) return 1;
    else if (v == 0) return 0;
    else return -1;
}
struct Fract{
    LL z, m;    
    LL gcd(LL a, LL b){
        while (b){
            LL r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    void Create(LL a, LL b = 1) {
        LL t = gcd(a, b);
        a /= t, b /= t;
        z = a, m = b;
        if (m < 0) m = -m, z = -z;
    }
    void print() {
        if (m == 1) printf("%lld", z); 
        else  printf("%lld/%lld", z, m);
    }
};
struct Point{
    LL x, y;
    // 与点p是否是为同一个点
    bool operator==(const Point &p){ 
        return x == p.x && y == p.y;
    }
    // 当前点p(x,y)与点p1和p2构成的向量p->p1、p->p2的叉积
    LL cross(const Point &p1, const Point &p2){
        return (p1.x - x)*(p2.y - y) - (p1.y - y)*(p2.x - x);
    }    
};
struct Segment{
    // 起点
    Point s;
    // 终点
    Point t;    
    // 线段的两个端点重合,则退化成一个点
    bool isPoint(){
        return s == t;
    }
    // 点p是否在线段上
    bool has(Point &p){
        if(cross(p) != 0) return false;
        if(s.x == t.x) 
            return p.y <= max(s.y, t.y) && p.y >= min(s.y, t.y);
        else
            return p.x <= max(s.x, t.x) && p.x >= min(s.x, t.x);
    }
    // 当前线段与线段seg是否重合
    bool operator==(const Segment &seg){
        return (s == seg.s && t == seg.t) || (s == seg.t && t == seg.s);
    }
    // 点p(x,y)与线段的端点构成的向量p->s、p->t的叉积
    LL cross(Point &p){
        return p.cross(s, t);
    }
    // 与线段seg相交
    // 返回值1:有一个交点,交点存储在x、y中
    // 返回值0:无交点
    // 返回值-1:无穷多个交点
    int interSection(Segment &seg, Fract &x, Fract &y){
        int res;
        if(isPoint() && seg.isPoint()){// 线段都是点
            if(*this == seg) res = 1, x.Create(s.x), y.Create(s.y);// 重合
            else res = 0;// 不重合 
        }
        else if(isPoint() || seg.isPoint()){// 有一线段是点
            if(isPoint() && seg.has(s))
                res = 1, x.Create(s.x), y.Create(s.y);
            else if(seg.isPoint() && has(seg.s))
                res = 1, x.Create(seg.s.x), y.Create(seg.s.y);            
            else
                res = 0;
        }
        else{// 线段都不是点
            LL a, b, c, d;
            int s1, s2, s3, s4;
            s1 = sign(a = seg.cross(s));
            s2 = sign(b = seg.cross(t));
            s3 = sign(c = this->cross(seg.s));
            s4 = sign(d = this->cross(seg.t));
            if((s1^s2) == -2 && (s3^s4) == -2){ // 1^-1 = -2
                res = 1;
                x.Create(b*s.x - a*t.x, b - a);
                y.Create(b*s.y - a*t.y, b - a);
            }
            else if(a == 0 && b == 0){
                if(seg.has(s) && seg.has(t))// 是seg子线段
                    res = -1;
                else if(seg.has(s)){ // s在线段seg上, t不在线段seg上
                    if((s == seg.s && !has(seg.t))||(s == seg.t && !has(seg.s)))
                        res = 1, x.Create(s.x), y.Create(s.y);
                    else
                        res = -1;
                }
                else if(seg.has(t)){// t在线段seg上, s不在线段seg上
                    if((t == seg.s && !has(seg.t))||(t == seg.t && !has(seg.s)))
                        res = 1, x.Create(t.x), y.Create(t.y);
                    else
                        res = -1;
                }
                else{
                    if(has(seg.s)) res = -1; // seg是子线段
                    else res = 0; // 无重叠
                }
            }
            else if(a == 0){ // b != 0
                if(seg.has(s)) res = 1, x.Create(s.x), y.Create(s.y);
                else res = 0;
            }
            else if(b == 0){ // a != 0
                if(seg.has(t)) res = 1, x.Create(t.x), y.Create(t.y);
                else res = 0;
            }
            else if(c == 0){ // d != 0
                if(has(seg.s)) res = 1, x.Create(seg.s.x), y.Create(seg.s.y);
                else res = 0;
            }
            else if(d == 0){ // c != 0
                if(has(seg.t)) res = 1, x.Create(seg.t.x), y.Create(seg.t.y);
                else res = 0;
            }
            else{ // a != 0 && b != 0
                res = 0;
            }
        }
        return res;
    }
};
int main()
{
    int T;
    Segment ab, cd;
    Fract x, y;    
    int res  ;
    scanf("%d", &T);
    while(T--){
        scanf("%lld %lld %lld %lld", &ab.s.x, &ab.s.y, &ab.t.x, &ab.t.y);
        scanf("%lld %lld %lld %lld", &cd.s.x, &cd.s.y, &cd.t.x, &cd.t.y);
        res = ab.interSection(cd, x, y);
        if(res == 1) {
            printf("1\n");
            x.print(), printf(" "), y.print();
            printf("\n");
        }
        else if (res == 0) printf("0\n"); 
        else printf("INF\n");
    }
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jpphy0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值