zoukankan      html  css  js  c++  java
  • POJ1556 The Doors 线段相交+最短路

    题意:在一个矩形平面内,有若干道墙,现求从左部某一点到右部某一点的最短路径。

    解法:有一个事实是线路一定是从门两边的点上通过的,不可能出现从中间穿过的可能。因此我们就枚举两两点之间是否可达,这里就要使用到线段相交的判定。构好图之后就是一个spfa搞定。

    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    using namespace std;
    
    int N;
    
    struct Wall {
        double x, a, b, c, d;
    }w[20];
    
    struct Point {
        double x, y;
    }e[105];
    int idx;
    
    struct Line {
        Point a, b;
        Line(Point x, Point y) {
            a = x, b = y;
        }
        friend bool cross(const Line &, const Line &);
    };
    
    double G[105][105];
    
    bool cross(const Line & Line1, const Line & Line2) {
        double Xa1 = Line1.a.x;
        double Ya1 = Line1.a.y;
        double Xa2 = Line1.b.x;
        double Ya2 = Line1.b.y;
        double Xb1 = Line2.a.x;
        double Yb1 = Line2.a.y;
        double Xb2 = Line2.b.x;
        double Yb2 = Line2.b.y;
        if(((Xa2-Xa1)*(Yb1-Ya1)-(Xb1-Xa1)*(Ya2-Ya1))*((Xa2-Xa1)*(Yb2-Ya1)-(Xb2-Xa1)*(Ya2-Ya1))>0)
            return false;
        if(((Xb2-Xb1)*(Ya1-Yb1)-(Xa1-Xb1)*(Yb2-Yb1))*((Xb2-Xb1)*(Ya2-Yb1)-(Xa2-Xb1)*(Yb2-Yb1))>0)
            return false;
        return true;
    }
    
    
    void insert(double x, double y) {
        e[idx].x = x, e[idx].y = y;
        ++idx;
    }
    
    bool legal(int x, int y) {
        Line line = Line(e[x], e[y]);
        int l = (x-1)/4, r = (y-1)/4; // 分别计算出这些点属于哪一面墙,再枚举中间的墙
        if (x == 0) l = -1;    // x==0时需特殊处理
        for (int i = l+1; i < r; ++i) { // 计算是否被墙挡住
            if (!cross(line, Line(e[i*4+1], e[i*4+2])) // 如果不从中间墙的某道门穿过的话 
             && !cross(line, Line(e[i*4+3], e[i*4+4]))) {
                return false;
            }
        }
        return true;
    }
    
    double dist(const Point & a, const Point & b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    void build() {
        for (int i = 0; i < idx; ++i) {
            for (int j = i + 1; j < idx; ++j) { // 枚举所有的两两组合 
                if (legal(i, j)) {
                    G[i][j] = dist(e[i], e[j]);
                }
            }
        }
    }
    
    #include <queue>
    bool vis[105];
    double dis[105];
    void spfa() {
        memset(vis, 0, sizeof (vis));
        for (int i = 0; i < idx; ++i) {
            dis[i] = 10000000;    
        }
        dis[0] = 0;
        queue<int>q;
        q.push(0);
        vis[0] = true;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
    vis[v] = false;
    for (int i = v+1; i < idx; ++i) { if (G[v][i] != 10000000 && dis[i] > dis[v] + G[v][i]) { dis[i] = dis[v] + G[v][i]; if (!vis[i]) { vis[i] = true; q.push(i); } } } } } int main() { while (scanf("%d", &N), N != -1) { for (int i = 0; i < 105; ++i) { for (int j = 0; j < 105; ++j) { G[i][j] = 10000000; } } idx = 0; insert(0.0, 5.0); for (int i = 0; i < N; ++i) { scanf("%lf %lf %lf %lf %lf", &w[i].x, &w[i].a, &w[i].b, &w[i].c, &w[i].d); insert(w[i].x, w[i].a), insert(w[i].x, w[i].b); insert(w[i].x, w[i].c), insert(w[i].x, w[i].d); // 读取所有的墙,并且添加四个点 } insert(10, 5); build(); spfa(); printf("%.2f\n", dis[idx-1]); } return 0; }
  • 相关阅读:
    源码剖析Django REST framework的请求生命周期
    Django REST framework中的版本控制
    Django REST framework反向生成url
    Django的ModelForm
    SQL Server 2008 R2导出数据脚本的方法
    未在本地计算机上注册 Microsoft.Jet.OLEDB.4.0 提供程序
    Webservice发布出现 测试窗体只能用于来自本地计算机的请求
    StreamWriter和StremReader简单的用法
    (转)PHP下编码转换函数mb_convert_encoding与iconv的使用说明
    (转)PHP中构造函数和析构函数解析
  • 原文地址:https://www.cnblogs.com/Lyush/p/2945921.html
Copyright © 2011-2022 走看看