zoukankan      html  css  js  c++  java
  • POJ 2556 (判断线段相交 + 最短路)

    题目: 传送门

    题意:在一个左小角坐标为(0, 0),右上角坐标为(10, 10)的房间里,有 n 堵墙,每堵墙都有两个门。每堵墙的输入方式为 x, y1, y2, y3, y4,x 是墙的横坐标,第一个门的区间为[ (x, y1) ~ (x, y2) ],问你从 (0, 5) 走到 (10, 5) 的最短路径是多少。 

    0 <= n <= 18

    题解:讲每个门的端点存起来,然后,加上(0, 5) 和 (10, 5) 这两个点,暴力判断这些点两两间是否能互相直达,然后再跑一遍最短路就行了。

          你不能直接从 (0, 5) 到 (10, 5) 那你肯定是经过一些门的端点再到终点是最优的。

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <vector>
    #include <set>
    #include <string>
    #include <math.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 1e20
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 1e2 + 5;
    const double eps = 1e-10;
    
    struct Point {
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) { } /// 构造函数
    };
    
    /// 向量加减乘除
    inline Point operator + (const Point& A, const Point& B) { return Point(A.x + B.x, A.y + B.y); }
    inline Point operator - (const Point& A, const Point& B) { return Point(A.x - B.x, A.y - B.y); }
    inline Point operator * (const Point& A, const double& p) { return Point(A.x * p, A.y * p); }
    inline Point operator / (const Point& A, const double& p) { return Point(A.x / p, A.y / p); }
    
    inline int dcmp(const double& x) { if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; }
    
    inline double Cross(const Point& A, const Point& B) { return A.x * B.y - A.y * B.x; } /// 叉积
    inline double Dot(const Point& A, const Point& B) { return A.x * B.x + A.y * B.y; } /// 点积
    inline double Length(const Point& A) { return sqrt(Dot(A, A)); } /// 向量长度
    inline double Angle(const Point& A, const Point& B) { return acos(Dot(A, B) / Length(A) / Length(B)); } /// 向量A,B夹角
    
    inline Point GetLineIntersection(const Point P, const Point v, const Point Q, const Point w) {///求直线p + v*t 和 Q + w*t 的交点,需确保有交点,v和w是方向向量
        Point u = P - Q;
        double t = Cross(w, u) / Cross(v, w);
        return P + v * t;
    }
    
    inline bool Onsegment(Point p, Point a1, Point a2) { /// 判断点p是否在线段p1p2上
        return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) <= 0;
    }
    
    inline bool SegmentProperInsection(Point a1, Point a2, Point b1, Point b2) { /// 判断线段是否相交
        if(dcmp(Cross(a1 - a2, b1 - b2)) == 0) /// 两线段平行
            return Onsegment(b1, a1, a2) || Onsegment(b2, a1, a2) || Onsegment(a1, b1, b2) || Onsegment(a2, b1, b2);
        Point tmp = GetLineIntersection(a1, a2 - a1, b1, b2 - b1);
        return Onsegment(tmp, a1, a2) && Onsegment(tmp, b1, b2);
    }
    
    Point P[N];
    double dis[N][N];
    int main() {
        int n;
        double x, y1, y2, y3, y4;
        while(scanf("%d", &n) && n != -1) {
    
            int cnt = 0;
            rep(i, 1, n) {
                scanf("%lf %lf %lf %lf %lf", &x, &y1, &y2, &y3, &y4);
                P[++cnt] = Point(x, y1);
                P[++cnt] = Point(x, y2);
                P[++cnt] = Point(x, y3);
                P[++cnt] = Point(x, y4);
            }
            
            rep(i, 0, cnt + 1) rep(j, 0, cnt + 1) if(i == j) dis[i][j] = 0; else dis[i][j] = INF;
    
            rep(i, 1, cnt) { /// 判断(0,5)是否能直达P[i],P[i]是否能直达(10,5)
                bool flag = 0; 
                int up = ((i + 3) / 4) * 4 + 1; 
                up -= 4;
                for(int j = 1; j < up; j += 4) { /// (0,5)是否能直达P[i]
                    if(SegmentProperInsection(P[j], P[j + 1], Point(0, 5), P[i]) == false && SegmentProperInsection(P[j + 2], P[j + 3], Point(0, 5), P[i]) == false) flag = 1;
                }
                if(!flag) dis[0][i] = dis[i][0] = Length(Point(0, 5) - P[i]);
    
                flag = 0;
                for(int j = up + 4; j <= cnt; j += 4) { /// P[i] 是否能直达(10,5)
                    if(SegmentProperInsection(P[j], P[j + 1], Point(10, 5), P[i]) == false && SegmentProperInsection(P[j + 2], P[j + 3], Point(10, 5), P[i]) == false) flag = 1;
                }
                if(!flag) dis[cnt + 1][i] = dis[i][cnt + 1] = Length(Point(10, 5) - P[i]);
            }
    
            rep(i, 1, cnt) rep(j, i + 1, cnt) { /// 枚举两点,判断这两点是否能直达
                int st = ((i + 3) / 4) * 4 + 1;
                int ed = ((j + 3) / 4) * 4;
                bool flag = 0;
                for(int k = st; k <= ed; k += 4) {
                    if(SegmentProperInsection(P[k], P[k + 1], P[i], P[j]) == false && SegmentProperInsection(P[k + 2], P[k + 3], P[i], P[j]) == false) flag = 1;
                }
                if(!flag) dis[i][j] = dis[j][i] = Length(P[i] - P[j]);
            }
    
            bool flag = 0;
            for(int i = 1; i <= cnt; i += 4) /// 判断(0,5)是否能直达(10,5)
                if(SegmentProperInsection(P[i], P[i + 1], Point(0, 5), Point(10, 5)) == false && SegmentProperInsection(P[i + 2], P[i + 3], Point(0, 5), Point(10, 5)) == false) flag = 1;
            if(!flag) dis[0][cnt + 1] = dis[cnt + 1][0] = 10;
    
            rep(k, 0, cnt + 1) rep(i, 0, cnt + 1) rep(j, 0, cnt + 1)
                if(dis[i][k] + dis[k][j] < dis[i][j]) dis[i][j] = dis[i][k] + dis[k][j];
            printf("%.2f
    ", dis[0][cnt + 1]);
        }
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    Android程序对不同手机屏幕分辨率自适应的方法
    用户管理和身份验证
    vue----scoped独立样式作用域
    vue----component动态组件
    css----行内元素&&块状元素
    html----rem结合vw布局
    js----jsonp原理
    js----白屏事件&&dom ready时间
    js----var a=b=2解析
    js----常见的表示false的有哪些
  • 原文地址:https://www.cnblogs.com/Willems/p/12377992.html
Copyright © 2011-2022 走看看