luogu 1354 房间最短路问题 线段与直线相交 最短路
题目链接
题目描述
在一个长宽均为10,入口出口分别为(0,5)、(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经。

输入输出格式
输入格式:
第一排为n(n<=20),墙的数目。
接下来n排,每排5个实数x,a1,b1,a2,b2。
x表示墙的横坐标(所有墙都是竖直的),a1-b1和a2-b2之间为空缺。
a1、b1、a2、b2保持递增,x1-xn也是递增的。
输出格式:
输出最短距离,保留2位小数。
输入输出样例
输入样例#1:
2
4 2 7 8 9
7 3 4.5 6 7
输出样例#1:
10.06
思路
将墙的端点抽象为点,将墙抽象为线段,在任意两个可以建边(没有被线段隔断)的端点之间加边。
跑一遍\(Floyd\).
小细节:如果可以与起始点连边,则无需与中间其他点再加边。
Code
#include <cstdio>
#include <cmath>
#define inf 1e200
#define eps 1e-6
using namespace std;
typedef long long LL;
struct Point {
    double x, y;
    Point(double _x=0, double _y=0) : x(_x), y(_y) {}
    Point operator + (const Point& b) const {
        return Point(x+b.x, y+b.y);
    }
    Point operator - (const Point& b) const {
        return Point(x-b.x, y-b.y);
    }
    double operator * (const Point& b) const {
        return x*b.x + y*b.y;
    }
    double operator ^ (const Point& b) const {
        return x*b.y - y*b.x;
    }
}point[20][4];
struct Seg {
    Point s, e;
    Seg(Point _s, Point _e) : s(_s), e(_e) {}
    Seg() {}
}wall[20][3];
double dist[100][100];
inline int id(int x, int y) { return 4*x+y-3; }
double euler_dist(Point a, Point b) {
    return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}
int sgn(double x) {
    if (fabs(x) < eps) return 0;
    if (x > 0) return 1;
    return -1;
}
double xmult(Point s, Point e, Point b) {
    return (s-b) ^ (e-b);
}
bool seg_inter_line(Point s, Point e, Seg l) {
    double v1 = xmult(s, e, l.s), v2 = xmult(s, e, l.e);
    return sgn(v1) * sgn(v2) < 0;
}
bool check(Point s, Point e, int l, int r) {
    for (int i = l; i < r; ++i) {
        for (int j = 0; j < 3; ++j) {
            if (seg_inter_line(s, e, wall[i][j])) return false;
        }
    }
    return true;
}
void build(Point e, int i, int j) {
    if (check(point[0][0], e, 1, i)) {
        dist[0][id(i,j)] = dist[id(i,j)][0] = euler_dist(point[0][0], point[i][j]);
        return;
    }
    for (int k = 1; k < i; ++k) {
        for (int t = 0; t < 4; ++t) {
            if (check(point[k][t], e, k+1, i)) {
                dist[id(k,t)][id(i,j)] = dist[id(i,j)][id(k,t)] = euler_dist(point[k][t], point[i][j]);
            }
        }
    }
}
int n;
void work() {
    point[0][0] = Point(0, 5); point[n+1][0] = Point(10, 5);
    for (int i = 0; i < 100; ++i) for (int j = i+1; j < 100; ++j) dist[i][j] = dist[j][i] = inf;
    for (int i = 1; i <= n; ++i) {
        double x,y1,y2,y3,y4;
        scanf("%lf%lf%lf%lf%lf", &x, &y1, &y2, &y3, &y4);
        point[i][0] = Point(x, y1), point[i][1] = Point(x, y2),
        point[i][2] = Point(x, y3), point[i][3] = Point(x, y4);
        wall[i][0] = Seg(Point(x, 0), point[i][0]),
        wall[i][1] = Seg(point[i][1], point[i][2]),
        wall[i][2] = Seg(point[i][3], Point(x, 10));
        for (int j = 0; j < 4; ++j) build(point[i][j], i, j);
    }
    build(point[n+1][0], n+1, 0);
    int tot = 4*n+2;
    for (int k = 0; k < tot; ++k) {
        for (int i = 0; i < tot; ++i) {
            for (int j = i+1; j < tot; ++j) {
                if (i == k || j == k) continue;
                if (dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[j][i] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    printf("%.2f\n", dist[0][tot-1]);
}
int main() {
    scanf("%d", &n);
    work();
    return 0;
}
												
											luogu 1354 房间最短路问题 线段与直线相交 最短路的更多相关文章
- 判断线段和直线相交 POJ 3304
		
// 判断线段和直线相交 POJ 3304 // 思路: // 如果存在一条直线和所有线段相交,那么平移该直线一定可以经过线段上任意两个点,并且和所有线段相交. #include <cstdio ...
 - POJ 1039 Pipe【经典线段与直线相交】
		
链接: http://poj.org/problem?id=1039 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
 - poj 3304线段与直线相交
		
http://poj.org/problem?id=3304 Segments Time Limit: 1000MS Memory Limit: 65536K Total Submissions: ...
 - poj 3304 Segments 线段与直线相交
		
Segments Time Limit: 1000MS Memory Limit: 65536K Description Given n segments in the two dim ...
 - luogu P1354 房间最短路问题 计算几何_Floyd_线段交
		
第一次写计算几何,还是很开心的吧(虽然题目好水qaq) 暴力枚举端点,暴力连边即可 用线段交判一下是否可行. Code: #include <cstdio> #include <al ...
 - [Luogu P1354]房间最短路问题
		
这是一道紫题,然而实际上我觉得也就蓝题难度甚至不到. and,这道题就是一道数学题,代码模拟计算过程. 求最短路嘛,肯定要考虑建图,只需要把中间的墙上每个口的边缘处的点作为图中的点就行.至于为什么,显 ...
 - POJ 3304 segments 线段和直线相交
		
Segments Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14178 Accepted: 4521 Descrip ...
 - HDU 4063 线段与圆相交+最短路
		
Aircraft Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
 - POJ3304 Segments 【线段直线相交】
		
题意: 给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!. 思路: 计算几何.这道题要思考到两点: 1:把问题转化为是否存在一条直线 ...
 
随机推荐
- 12_1_Annotation注解
			
12_1_Annotation注解 1. 什么是注解 Annotation是从JDK5.0开始引入的新技术. Annotation的作用: 不是程序本身,可以对程序作出解释.可以被其他程序(比如,编译 ...
 - 字节跳动后端开发实习生面试(Python)
			
一面: 1.自我介绍. 2.介绍“工大小美”项目相关. 3.Python中的GIL(全局解释器锁),以及哪种情况下使用python的多线程性能有较大的提升. 4.项目中用到了SQLite数据库,如果有 ...
 - 标准C++(4)继承
			
一.继承的作用 若A类继承了B类,可以使A类获得B类中的部分成员变量和成员函数,这能使程序员在已有类的基础上重新定义新的类.继承是类的重要特性,当A类继承了B类,我们称A类为派生类或子类,B类为基类或 ...
 - python入门:BREAK 的用法  跳当前循环后,不再执行下面代码块
			
#!/urs/bin/env python # -*- coding:utf-8 -*- # BREAK 的作用 跳当前循环后,不再执行下面代码块 while True: ') break ') #w ...
 - python 类的封装/property类型/和对象的绑定与非绑定方法
			
目录 类的封装 类的property特性 类与对象的绑定方法与非绑定方法 类的封装 封装: 就是打包,封起来,装起来,把你丢进袋子里,然后用绳子把袋子绑紧,你还能拿到袋子里的那个人吗? 1.隐藏属性和 ...
 - GoF23种设计模式之行为型模式之解释器模式
			
一.概述 给定一种语言和其文法的一种表示,再定义一个解释器,该解释器使用表示来解释语言中的句子. 二.适用性 当需要解释一种语言,并且可以将该语言中的句子表示 ...
 - Python学习笔记:py2exe打包Python程序
			
使用py2exe将一个Python程序打包成一个exe程序,这样Python程序也可以在没有安装Python的环境中运行Python程序了.使用这个工具需要写一个用于打包的setup.py文件(名称可 ...
 - LeetCode(258) Add Digits
			
题目 Given a non-negative integer num, repeatedly add all its digits until the result has only one dig ...
 - ubuntu12.04ppa安装emacs24
			
ppa地址:https://launchpad.net/~cassou/+archive/emacs 因为debian版本的emacs-snapshot维护者停止更新,所有ubuntu上的也停止了. ...
 - 给vagrant中的precise64升级VBoxGuestAdditions
			
位置:/usr/share/virtualbox/VBoxGuestAdditions.iso 在host(ubuntu 12.04 64)中: 查看虚拟机的名字:jb@H38:~/vm/vagran ...