描述

在一个长宽均为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

样例输入1[复制]

2
4 2 7 8 9
7 3 4.5 6 7

样例输出1[复制]

10.06


【题解】

这是一道最短路问题。

这样做。

给每个墙上的两个“裂缝”的端点标号。则每个墙有4个端点(起点和终点除外)。

则第i个墙的第j个端点它的编号为(i - 1) + j;

然后起点的编号为0,终点的编号为4*n + 1;

最后输出0到4*n+1的最短距离;

然后建图的过程如下

枚举第ii个墙和第jj个墙

然后第ii个墙枚举的是第i个端点,第jj个墙枚举的是第j个端点。

设两个端点的坐标为(x1,y1),(x2,y2);

然后我们就要看看ii+1..jj-1这些墙里面是否有会挡住这两点所构成的直线的墙。

如果有这样的墙,则这两个点不能连线,否则在它们两个点之间建立一条边。

这条边的权值就是两点之间的距离。

可以用两点之间的距离公式求得。

sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

然后要判断会不会有墙挡住这条直线则需要用到直线方程的两点式;

已知两个点(x1,y1),(x2,y2);

则它们所构成的直线方程为

(x-x1)/(x2-x1)=(y-y1)/(y2-y1)

然后两边消一下,换一下。

得到y=(y2-y1)*(x-x1)/(x2-x1) + y1

然后假设我们枚举到ii+1..jj-1中的墙k。

则x=墙k的横坐标

代入之后得到y0;

看看这个y0是不是在k墙的两个窟窿中。如果不是则会撞墙返回false跳过这条边。

如果ii+1..jj-1这些墙都不会阻碍这条直线。则可以在这两个点之间建一条边。

然后还要单独处理起点到其他墙的、其他墙到终点的以及起点到终点的这3种情况。

最后选择用floyd来求最短路即可(简单!)

【代码】

#include <cstdio>
#include <cmath>
#include <cstring> struct point
{
double x;
double height[5];
}; int n, t[200][200] = { 0 };
double w[200][200];
point a[200]; int main()
{
for (int i = 0; i <= 199; i++)
for (int j = 0; j <= 199; j++) //这是做floyd算法用的数组。一开始赋值为无穷大。
w[i][j] = 2100000000 / 3;
scanf("%d", &n);
for (int i = 1; i <= n; i++) //输入n个墙的信息。
{
double x, a1, b1, a2, b2;
scanf("%lf%lf%lf%lf%lf", &x, &a1, &b1, &a2, &b2);
a[i].x = x, a[i].height[1] = a1, a[i].height[2] = b1, a[i].height[3] = a2, a[i].height[4] = b2;
} for (int ii = 2; ii <= n; ii++) //第ii列
{
for (int i = 1;i <= 4;i++)
for (int jj = 1; jj <= ii - 1; jj++) //第jj列
{
for (int j = 1; j <= 4; j++) //这层要先求出i,j两个点构成的直线方程。
{
double x1, y1, x2, y2;
x1 = a[ii].x;y1 = a[ii].height[i]; //这是所枚举的两个点的坐标。
x2 = a[jj].x;y2 = a[jj].height[j];
bool judge = true;
for (int kk = jj + 1; kk <= ii - 1; kk++)//它们中间的墙。
{
double x = a[kk].x;
double y0 = ((y2 - y1)*(x - x1) / (x2 - x1)) + y1; //这是这两列的相应的点的直线方程,把第kk列的点的信息代入。
if ((y0 >= a[kk].height[1] && y0 <= a[kk].height[2]) || (y0 >= a[kk].height[3] && y0 <= a[kk].height[4]))
judge = true; //如果在两个窟窿里面则是可以添加的边
else//否则只要有一个不行就判错
{
judge = false;
break;//结束循环了。
}
}
if (judge) //如果可以添加这条边
{
int fr = (jj - 1) * 4 + j, to = (ii - 1) * 4 + i;//这是两个点的编号。
t[fr][0]++; //起点的出度增加。
t[fr][t[fr][0]] = to;
w[fr][to] = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));//权值为两点之间的距离。
}
}
}
} //其实下面这两段直接复制上面的同时枚举两个点的片段即可。 for (int jj = 1; jj <= n; jj++) //这是起点到其他墙的点。(不包括终点)
{
for (int j = 1; j <= 4; j++)
{
double x1, y1, x2, y2;
x1 = 0; y1 = 5; //这下其中的一个点变成是固定的了。
x2 = a[jj].x; y2 = a[jj].height[j];//现在只需要枚举一个点了。
bool judge = true;
for (int kk = 1; kk <= jj- 1; kk++)//然后枚举它们中间的墙,如果它们中间没有墙,则说明一定可以添加,所以初值是true;
{
double x = a[kk].x;
double y0 = ((y2 - y1)*(x - x1) / (x2 - x1)) + y1;//用同样的办法判断是否可以添加这条边。
if ((y0 >= a[kk].height[1] && y0 <= a[kk].height[2]) || (y0 >= a[kk].height[3] && y0 <= a[kk].height[4]))
judge = true;
else
{
judge = false;
break;
}
}
if (judge)
{
int fr = 0, to = (jj - 1) * 4 + j;//如果可以就添加这条边。
t[fr][0]++;
t[fr][t[fr][0]] = to;
w[fr][to] = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
}
} for (int jj = 1; jj <= n; jj++) //其他墙上的点(不包括起点)到终点(4*n+1)
{
for (int j = 1; j <= 4; j++)
{
double x1, y1, x2, y2;
x1 = a[jj].x; y1 = a[jj].height[j];
x2 = 10; y2 = 5;//这下其中一个固定的点变成了终点
bool judge = true;
for (int kk = jj+1; kk <= n; kk++)
{
double x = a[kk].x;
double y0 = ((y2 - y1)*(x - x1) / (x2 - x1)) + y1;
if ((y0 >= a[kk].height[1] && y0 <= a[kk].height[2]) || (y0 >= a[kk].height[3] && y0 <= a[kk].height[4]))
judge = true;
else
{
judge = false;
break;
}
}
if (judge) //如果可以则添加这条边。
{
int fr = (jj - 1) * 4 + j, to = 4*n+1;
t[fr][0]++;
t[fr][t[fr][0]] = to;
w[fr][to] = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
}
} //起点到终点,因为可能可以直接从起点画一条直线就到终点了。所以一定要判断这个。不然会WA!
double x1, y1, x2, y2;
x1 = 0; y1 = 5;
x2 = 10; y2 = 5; //两个点都是固定的了。
bool judge = true;
for (int kk = 1; kk <= n; kk++)//看看起点和终点直接的墙会不会阻碍它们俩画一条直线。
{
double x = a[kk].x;
double y0 = ((y2 - y1)*(x - x1) / (x2 - x1)) + y1;
if ((y0 >= a[kk].height[1] && y0 <= a[kk].height[2]) || (y0 >= a[kk].height[3] && y0 <= a[kk].height[4]))
judge = true;
else
{
judge = false;
break;
}
}
if (judge)//如果不会被阻碍,就画一条边。
{
int fr = 0, to = 4 * n + 1;
t[fr][0]++;
t[fr][t[fr][0]] = to;
w[fr][to] = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
} n = 4 * n + 1;//让n变成节点的编号。
for (int k = 0; k <= n; k++)//从0-n做floyd;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
if (w[i][j] > w[i][k] + w[k][j])
w[i][j] = w[i][k] + w[k][j];
printf("%.2lf", w[0][n]); //保留两位小数输出即可。
return 0;
}

【u026】房间最短路问题的更多相关文章

  1. P1354 房间最短路问题

    传送门 可以发现,最短路一定要经过墙壁的断点. 那么把房间看作一个有向图,墙壁的断点为节点,求从起点到终点的最短路. 这道题的难点在于建图.枚举所有的断点,若可以走则加入这条边. 判断两点是否连通,即 ...

  2. luogu 1354 房间最短路问题 线段与直线相交 最短路

    题目链接 题目描述 在一个长宽均为10,入口出口分别为(0,5).(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经. 输入输出格式 输入格式: 第一排为n(n<=20) ...

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

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

  4. luoguP1354房间最短路问题

    判断两点间连通性,建图跑floyed #include<bits/stdc++.h> using namespace std; ; struct node { ],x; }q[N];dou ...

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

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

  6. ACM/ICPC 之 DP解有规律的最短路问题(POJ3377)

    //POJ3377 //DP解法-解有规律的最短路问题 //Time:1157Ms Memory:12440K #include<iostream> #include<cstring ...

  7. ACM 房间安排

    房间安排 时间限制:3000 ms  |  内存限制:65535 KB 难度:2   描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至10月31日期间, ...

  8. 房间安排-nyoj168

    描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至10月31日期间,在中国上海市举行.本次世博会也是由中国举办的首届世界博览会.上海世博会以“城市,让生活 ...

  9. 房间声学原理与Schroeder混响算法实现

    一.混响时间的计算与预测 所谓混响就是声音的直达声与反射声很紧凑的重合在一起时人耳所听到的声音,这个效果在语音的后期处理时特别有用.能产生混响最常见的场景就是房间内,尤其是空旷的房间中. 混响有直达声 ...

随机推荐

  1. Spider_lxml

    xpath工具(解析) xpath 在XML文档中查找信息的语言,同样适用于HTML文档的检索 xpath辅助工具 Chrome插件 :XPath Helper 打开 :Ctrl + Shift + ...

  2. C# 解决ListView控件显示数据出现闪屏的问题

    一.发现问题 如果发送数据过快的情况下,ListVies滚屏显示数据时会显示闪屏,如下所示现象: 二.解决问题 根据出现闪屏的情况,在网上查了资料要使用双缓存的办法来处理.其原理是数据在缓存区中进行处 ...

  3. 洛谷 P2819 图的m着色问题

    P2819 图的m着色问题 题目背景 给定无向连通图G和m种不同的颜色.用这些颜色为图G的各顶点着色,每个顶点着一种颜色.如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的.图的 ...

  4. Android-ViewPager+Fragment数据更新问题

    由于FragmentPagerAdapter内部存在缓存.因此调用notifyDataSetChanged()并不可以去更新Fragment的内容. 參考:http://www.devba.com/i ...

  5. [Ramda] Simple log function for debugging Compose function / Using R.tap for logging

    const log = function(x){ console.log(x); return x; } const get = R.curry(function(prop, obj){ return ...

  6. Js里面的arguments

    了解这个对象之前先来认识一下javascript的一些功能: 其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载.Javascrip中国每个函数都会有一个Argume ...

  7. C语言深度剖析-----函数与指针的分析

                          指针的本质 指针需要保证指向任意数据类型,所以指针变量都占用32位bit即4字节. PS:不同机器上,指针占用内存不一                   ...

  8. 大话Spark(8)-源码之DAGScheduler

    DAGScheduler的主要作用有2个: 一.把job划分成多个Stage(Stage内部并行运行,整个作业按照Stage的顺序依次执行) 二.提交任务 以下分别介绍下DAGScheduler是如何 ...

  9. VSX(翻译)Moving Code Blocks Among Code Regions using VS 2010 Extensions

    Moving Code Blocks Among Code Regions using VS 2010 Extensions (翻译)使用VS 2010 扩展性将代码块移至Region区域中 Down ...

  10. 嵌入式arm linux环境中gdb+gdbserver调试

    一.前言嵌入式Linux系统中,应用开发过程中,很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序.采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采 ...