2018 China Collegiate Programming Contest - Guilin Site ccpc 桂林 L - Two Ants计算几何

题意

给你一条黑线和一条白线,问仅能看到白线的区域面积是多少。

分析

情况大概有以下这么多种:

  1. 两线段相交:
    端点处相交,是否共线
    一条线段端点在另一条线段上
    两条线段在非端点处相交
  2. 两线段不相交
    两线段所在直线相交,相交与黑线/白线
    对应端点做出如样例3的两条直线,判断交点是否在黑线和白线的同一侧,考虑是否交换某一线段的两端点
    最后判断交点与黑白线的关系,求出对应面积或inf
    4LojC6.jpg

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define endl '\n'
const int N = 1e6 + 10, M = N * 2;
const double eps = 1e-8;
int sgn(double d){
	if(fabs(d) < eps) return 0;
    if(d > 0) return 1;
    return -1;
}
struct Point {
    double x, y;
    Point (double x = 0, double y = 0) : x(x), y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A, Vector B) {
    return Vector (A.x + B.x, A.y + B.y);
}
Vector operator - (Vector A, Vector B) {
    return Vector (A.x - B.x, A.y - B.y);
}
Vector operator * (Vector A, double p) {
    return Vector (A.x * p, A.x * p);
}
Vector operator / (Vector A, double p) {
    return Vector (A.x / p, A.x / p);
}
double Dot (Vector A, Vector B) {
    return A.x * B.x + A.y * B.y;
}
double Cross(Vector A, Vector B) {
    return A.x * B.y - A.y * B.x;
}
double Length(Vector A) {
    return sqrt(A.x * A.x + A.y * A.y);
}
double Dist(Vector A, Vector B) {
    double dx = A.x - B.x, dy = A.y - B.y;
    return sqrt(dx * dx + dy * dy);
}
Point getIntersectPoint(Point p1, Point p2, Point p3, Point p4){
    double a1 = p1.y - p2.y, b1 = p2.x - p1.x, c1 = p1.x * p2.y - p2.x * p1.y;
    double a2 = p3.y - p4.y, b2 = p4.x - p3.x, c2 = p3.x * p4.y - p4.x * p3.y;
    return Point ((c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2), (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1));
}
bool is_segment_intersection(Point p1, Point p2, Point p3, Point p4){
    if(max(p3.x, p4.x) < min(p1.x, p2.x) || max(p1.x, p2.x) < min(p3.x, p4.x)) return 0;
    if(max(p3.y, p4.y) < min(p1.y, p2.y) || max(p1.y, p2.y) < min(p3.y, p4.y)) return 0;
    if(Cross(p1 - p4, p3 - p4) * Cross(p2 - p4, p3 - p4) > 0) return 0;
    if(Cross(p4 - p2, p1 - p2) * Cross(p3 - p2, p1 - p2) > 0) return 0;
    return 1;
}
bool OnSegment(Point p, Point p1, Point p2){
	return sgn(Cross(p - p1, p2 - p1)) == 0 && sgn(Dot(p - p1, p - p2)) <= 0;
}
bool operator == (Point a, Point b) {
    return fabs(a.x - b.x) < eps && fabs(a.y - b.y) < eps;
}
bool is_Parallel(Point p1, Point p2, Point p3, Point p4){
    return sgn(Cross(p1 - p2, p3 - p4)) == 0;
}
int t;
Point w1, w2, b1, b2, Jiao;

void doit(int cas) {
    cout << "Case "<<cas<<": " ;
    cin >> w1.x >> w1.y >> w2.x >> w2.y;
    cin >> b1.x >> b1.y >> b2.x >> b2.y;
    if(w1 == b1 || w1 == b2 || w2 == b1 || w2 == b2) {
        if(sgn(Cross(b2 - b1 ,w2 - w1)) == 0) cout << 0 << '\n';
        else cout << "inf" << '\n';
        return;
    }
    if(is_segment_intersection(b1, b2, w1, w2)) {
        if(OnSegment(b1, w1, w2) || OnSegment(b2, w1, w2)) cout << "inf" << '\n';
        else if(OnSegment(w1, b1, b2) || OnSegment(w2, b1, b2))cout << 0 << '\n';
        else cout << 0 << '\n';
        return;
    }
    // 直线共线
    if(sgn(Cross(w1 - b1, w1 - b2)) == 0 && sgn(Cross(w2 - b1, w2 - b2)) == 0) {
        cout << 0 << '\n';
        return;
    }
    if(!is_Parallel(b1, b2, w1, w2)) {
        Jiao = getIntersectPoint(b1, b2, w1, w2);
        if(OnSegment(Jiao, b1, b2) || Jiao == b1 || Jiao == b2) {
            cout << 0 << '\n';
            return;
        }else if(OnSegment(Jiao, w1, w2) || Jiao == w1 || Jiao == w2) {
            cout << "inf" << '\n';
            return;
        }
    }
    if(is_segment_intersection(w1, b1, w2, b2)) {
        swap(w1, w2);
    }
    if(is_Parallel(b1, w1, b2, w2)){
        cout << "inf" << '\n';
        return ;
    }
    Jiao = getIntersectPoint(w1, b1, w2, b2);
    double s1 = Cross(w2 - w1, Jiao - w1), s2 = Cross(w2 - w1, b1 - w1);
    if(s1 * s2 > 0) cout << "inf" << '\n';
    else {
        double ans = fabs(s1) / 2.0;
        cout << setiosflags(ios::fixed) << setprecision(8) << ans << '\n';
    }
}
int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> t;
    for (int _ = 1; _ <= t; _++){
        doit(_);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值