题目链接

题目描述

在一个长宽均为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 房间最短路问题 线段与直线相交 最短路的更多相关文章

  1. 判断线段和直线相交 POJ 3304

    // 判断线段和直线相交 POJ 3304 // 思路: // 如果存在一条直线和所有线段相交,那么平移该直线一定可以经过线段上任意两个点,并且和所有线段相交. #include <cstdio ...

  2. POJ 1039 Pipe【经典线段与直线相交】

    链接: http://poj.org/problem?id=1039 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...

  3. poj 3304线段与直线相交

    http://poj.org/problem?id=3304 Segments Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: ...

  4. poj 3304 Segments 线段与直线相交

    Segments Time Limit: 1000MS   Memory Limit: 65536K       Description Given n segments in the two dim ...

  5. luogu P1354 房间最短路问题 计算几何_Floyd_线段交

    第一次写计算几何,还是很开心的吧(虽然题目好水qaq) 暴力枚举端点,暴力连边即可 用线段交判一下是否可行. Code: #include <cstdio> #include <al ...

  6. [Luogu P1354]房间最短路问题

    这是一道紫题,然而实际上我觉得也就蓝题难度甚至不到. and,这道题就是一道数学题,代码模拟计算过程. 求最短路嘛,肯定要考虑建图,只需要把中间的墙上每个口的边缘处的点作为图中的点就行.至于为什么,显 ...

  7. POJ 3304 segments 线段和直线相交

    Segments Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14178   Accepted: 4521 Descrip ...

  8. HDU 4063 线段与圆相交+最短路

    Aircraft Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  9. POJ3304 Segments 【线段直线相交】

    题意: 给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!. 思路: 计算几何.这道题要思考到两点: 1:把问题转化为是否存在一条直线 ...

随机推荐

  1. 标准C++(4)继承

    一.继承的作用 若A类继承了B类,可以使A类获得B类中的部分成员变量和成员函数,这能使程序员在已有类的基础上重新定义新的类.继承是类的重要特性,当A类继承了B类,我们称A类为派生类或子类,B类为基类或 ...

  2. tab key usage

    QA:gvim编辑ascii文本时由于tabkey的default setting 不合适编写Verilog代码(比如一个tab 代表多少空格) ANS: 1.tab 的自动补齐有两种usage自动补 ...

  3. 【php】instanceof

    instanceof 的使用还有一些陷阱必须了解.在 PHP 5.1.0 之前,如果要检查的类名称不存在,instanceof 会调用__autoload().另外,如果该类没有被装载则会产生一个致命 ...

  4. Decorator——Python初级函数装饰器

    最近想整一整数据分析,在看一本关于数据分析的书中提到了(1)if __name__ == '__main__' (2)列表解析式 (3)装饰器. 先简单描述一下前两点,再详细解说Python初级的函数 ...

  5. numpy 三个点的使用[...]

    numpy [...]语法简单使用 Python numpy中切片功能与列表切片类似,但功能更加强大 本文主讲numpy中[...]的简单使用,后续工作继续补充. import numpy >& ...

  6. 通过代码链接ftp上传下载删除文件

    因为我的项目是Maven项目,首先要导入一个Maven库里的包:pom.xml <dependency>            <groupId>com.jcraft</ ...

  7. python 中 * 与**的使用

    1.参数中使用如果是函数定义中参数前的*表示的是将调用时的多个参数放入元组中,**则表示将调用函数时的关键字参数放入一个字典中 如定义以下函数 def func(*args): print(args) ...

  8. gdb调试时查看内存

    x/<n/f/u> <addr> n.f.u是可选的参数,<addr>表示一个内存地址 1) n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地 ...

  9. AreYouBusy HDU - 3535 (dp)

    AreYouBusy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  10. Linux学习-什么是 daemon 与服务 (service)

    『常驻在记体体中的程序,且可以提供 一些系统或网络功能,那就是服务』.而服务一般的英文说法是『 service 』. 那么 daemon 与 service 有关啰?否则为什么都能够提供 某些系统或网 ...