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;
}