【u026】房间最短路问题
描述
在一个长宽均为10,入口出口分别为(0,5)、(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经。
在一个长宽均为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也是递增的。
第一排为n(n<=20),墙的数目。
接下来n排,每排5个实数x,a1,b1,a2,b2。
x表示墙的横坐标(所有墙都是竖直的),a1-b1和a2-b2之间为空缺。
a1、b1、a2、b2保持递增,x1-xn也是递增的。
输出格式
输出最短距离,保留2位小数。
输出最短距离,保留2位小数。
样例1
样例输入1[复制]
2
4 2 7 8 9
7 3 4.5 6 7
2
4 2 7 8 9
7 3 4.5 6 7
样例输出1[复制]
10.06
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】房间最短路问题的更多相关文章
- P1354 房间最短路问题
传送门 可以发现,最短路一定要经过墙壁的断点. 那么把房间看作一个有向图,墙壁的断点为节点,求从起点到终点的最短路. 这道题的难点在于建图.枚举所有的断点,若可以走则加入这条边. 判断两点是否连通,即 ...
- luogu 1354 房间最短路问题 线段与直线相交 最短路
题目链接 题目描述 在一个长宽均为10,入口出口分别为(0,5).(10,5)的房间里,有几堵墙,每堵墙上有两个缺口,求入口到出口的最短路经. 输入输出格式 输入格式: 第一排为n(n<=20) ...
- [Luogu P1354]房间最短路问题
这是一道紫题,然而实际上我觉得也就蓝题难度甚至不到. and,这道题就是一道数学题,代码模拟计算过程. 求最短路嘛,肯定要考虑建图,只需要把中间的墙上每个口的边缘处的点作为图中的点就行.至于为什么,显 ...
- luoguP1354房间最短路问题
判断两点间连通性,建图跑floyed #include<bits/stdc++.h> using namespace std; ; struct node { ],x; }q[N];dou ...
- luogu P1354 房间最短路问题 计算几何_Floyd_线段交
第一次写计算几何,还是很开心的吧(虽然题目好水qaq) 暴力枚举端点,暴力连边即可 用线段交判一下是否可行. Code: #include <cstdio> #include <al ...
- ACM/ICPC 之 DP解有规律的最短路问题(POJ3377)
//POJ3377 //DP解法-解有规律的最短路问题 //Time:1157Ms Memory:12440K #include<iostream> #include<cstring ...
- ACM 房间安排
房间安排 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至10月31日期间, ...
- 房间安排-nyoj168
描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至10月31日期间,在中国上海市举行.本次世博会也是由中国举办的首届世界博览会.上海世博会以“城市,让生活 ...
- 房间声学原理与Schroeder混响算法实现
一.混响时间的计算与预测 所谓混响就是声音的直达声与反射声很紧凑的重合在一起时人耳所听到的声音,这个效果在语音的后期处理时特别有用.能产生混响最常见的场景就是房间内,尤其是空旷的房间中. 混响有直达声 ...
随机推荐
- vmware workstation安装windows server 2019
提示需要输入密钥,选择[我没有密钥] 选择有桌面体验的 自定义 新建C盘 100G 选择100G的主分区,下一步 PS:未分配的空间,先不理,安装完系统,进桌面,再分配 开始安装.接下来就是等. 等. ...
- 高中生活-第9篇-开学之初的“失足”囧事,"刻舟求剑"导致腿折了
时间过得好快啊,上次发表"高中生活-第8篇:夏天的空调,冬天的味道"是2014年9月30日,一转眼,就是一年啊. 我自己以为,很多人可能都以为,我又半途而废了,实则不是哦~ 行百里 ...
- 想知道WiFi是什么样子的么?
据英国<每日邮报>报道.英国纽卡斯尔大学博士生路易斯·赫南日前利用定制的仪器为WiFi信号拍照,绘制出一系列展现人类周围无形网络WiFi连接情况的图,这些盘旋环绕的明亮光束,宛如幽灵一般缠 ...
- Netty推荐addListener回调异步执行
说明 Netty推荐使用addListener的方式来回调异步执行的结果,这种方式优于Future.get,能够更精确地把握异步执行结束的时间. 错误理解使用addListener的方式 代码如下: ...
- Android Studio com.android.dex.DexException: Multiple dex files define(重复引用包)
如果你用Android Studio开发,并且要用其他项目作为library,这个问题是很容易出现的.出现这个问题的原因是包的重复引用,意思就是在你自己的项目中引用了某个包,而被你作为library的 ...
- 利用Socket进行大文件传输
分类: WINDOWS 最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图): 所以,我们需要三个socket在窗体加载的时候初始化: ...
- Tomcat源代码阅读#1:classloader初始化
Bootstrap 通过Tomcat的启动脚本能够看到启动的入口是在Bootstrap,来看下Bootstrap的main方法, /** * Main method and entry point w ...
- Android 软键盘弹出,界面整体上移的问题
AndroidManifest.xml文件中界面对应的<activity>里加入android:windowSoftInputMode="adjustPan" 键盘就会 ...
- 芯片TPS76030、TPS76032、TPS76033、TPS76038、TPS76050 电源芯片
下图是从网上摘出来的图片:TPS76033 它的作用就是改变电压: 输入电压:3.5V到16V 通过芯片的处理后 输出电压:3.3V 要学会看图,从中提取有用的信息 再看一个数据手 ...
- Textillate.js有什么用及使用实例
Textillate.js有什么用及使用实例 一.总结 一句话总结:Textillate.js – 实现动感的 CSS3 文本动画的简单插件 二.textillate.js 文字动画 textilla ...