【最短路算法例题-升降梯上】-C++
描述
启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。
Nescafe之塔一共有N层,升降梯在每层都有一个停靠点。手柄有M个控制槽,第i个控制槽旁边标着一个数C_i,满足C1<C2<C3<...<CM。如果Ci>0,表示手柄扳动到该槽时,电梯将上升Ci层;如果Ci<0,表示手柄扳动到该槽时,电梯将下降 −Ci层;并且一定存在一个Ci=0,手柄最初就位于此槽中。注意升降梯只能在1~N层间移动,因此扳动到使升降梯移动到1层以下、N层以上的控制槽是不允许的。
电梯每移动一层,需要花费2秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费1秒钟时间。探险队员现在在1层,并且想尽快到达N层,他们想知道从1层到N层至少需要多长时间?
输入
第一行两个正整数N、M。
第二行M个整数C_1、C_2、...、C_M。
输出
输出一个整数表示答案,即至少需要多长时间。若不可能到达输出-1。
输入样例 1
6 3
-1 0 2
输出样例 1
19
提示
数据范围:
1 <= n <= 1000
1 <= m <= 20
样例分析:
手柄从第二个槽扳到第三个槽(0扳到2),用时1秒,电梯上升到3层,用时4秒。
手柄在第三个槽不动,电梯再上升到5层,用时4秒。
手柄扳动到第一个槽(2扳到-1),用时2秒,电梯下降到4层,用时2秒。
手柄扳动到第三个槽(-1扳倒2),用时2秒,电梯上升到6层,用时4秒。
总用时为(1+4)+4+(2+2)+(2+4)=19秒。
这道题说实话,我刚做的时候看不出用什么办法来做。所以我选择了:
广搜!
每个状态分别为:当前楼层,花费时间,拉杆目前位置。
但是搜索一波出来发现:
只能过两组!
为什么呢?
很明显,光凭借广搜,我们无法一次得出最优的答案。所以我们就要考虑使用其他方法。
根据机房大佬和老师的帮助 ,这道题的正解是最短路!
那么怎么构图?
这就是这道题的核心问题。再次经过冥思苦想(确信),我们在二维的状态下,可以用dst[i][j]表示从拉杆位置在j时上到第i层所需要的时间。
但是二维的状态我们难以形成最短路。
那怎么办?
二维转一维!
直接写一个convert函数,把一个数对转换成一个编号。那么:
int convert(int x,int y)
{
return (x-1)*m+y;
}
接下来就是构图。
构图我的方法比较麻烦,用到了三层循环。大概代码如下:
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=m;k++)
{
int u=convert(i,j),v=convert(i+c[k],k),w=abs(j-k)+abs(2*c[k]);
g[u].push_back(node(v,w));
}
}
}
因为我用到的是迪杰斯特拉算法(不了解的看看这篇博客再继续看下去哈),所以用到的是二维结构体vector来存图。前置定义如下
struct node
{
int v,w;
node(){}
node(int vv,int ww)
{
v=vv,w=ww;
}
};
vector<node> g[200010];
然后就可以用最短路模板来AC这道题目了,但是要注意的是,这道题的点数不是n,而是n*m!因为我们是把二维转成的一维,所以点数要乘上可能到达这个点的拉杆槽的数量!
最短路函数主体:
void dij(int p)
{
for(int i=1;i<=200010;i++)
{
dst[i]=INF;
s[i]=0;
}
s[p]=1;
dst[p]=0;
int lasti=p;
for(int k=1;k<n*m;k++)
{
for(int j=0;j<g[lasti].size();j++)
{
int v=g[lasti][j].v,w=g[lasti][j].w;
if(!s[v]&&dst[v]>w+dst[lasti])
{
dst[v]=w+dst[lasti];
}
}
int min_i=INF,min_dst=INF;
for(int i=1;i<=n*m;i++)
{
if(!s[i])
{
if(dst[i]<min_dst)
{
min_dst=dst[i];
min_i=i;
}
}
}
lasti=min_i;
s[min_i]=1;
}
}
最后一个问题:
我们最后输出啥?
最短路已经找出来,但是我们能直接输出dst[n]吗?
很明显不行!!!
我们的dst数组的每一个下标,对应的是一个数对,而不是一个点!
所以,我们要从以convert(n,1)为下标的dst值遍历到以convert(n,m)为下标的dst值,最后输出最小值即可。一个循环就可以搞定。
但是别忘了!题目中还有个输出"-1"的判断需求,需要注意的是,当我们无法到达第n楼的时候,对于任意一个小于m的i,dst[n] [convert(n,i)]的值是不会改变的!所以我们只需要在输出的时候判断一下ans是否有更新操作,没有就输出-1.
这一步代码如下:
int ans=INF;
for(int i=1;i<=m;i++)
{
int r=convert(n,i);
ans=min(ans,dst[r]);
}
if(ans!=INF)
cout<<ans<<endl;
else cout<<-1<<endl;
这是为了判断题中的特殊情况。
为了配合最终答案在 “无解” 的情况下dst[n]的任意值不会更新的特性,我们要在迪杰斯特拉的最外层循环的最后加上一句:
if(min_i==INF)return;
完整代码如下:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int c[1000010],n,m;
bool s[1000010];
int convert(int x,int y)
{
return (x-1)*m+y;
}
int dst[200010];
struct node
{
int v,w;
node(){}
node(int vv,int ww)
{
v=vv,w=ww;
}
};
vector<node> g[200010];
void dij(int p)
{
for(int i=1;i<=200010;i++)
{
dst[i]=INF;
s[i]=0;
}
s[p]=1;
dst[p]=0;
int lasti=p;
for(int k=1;k<n*m;k++)
{
for(int j=0;j<g[lasti].size();j++)
{
int v=g[lasti][j].v,w=g[lasti][j].w;
if(!s[v]&&dst[v]>w+dst[lasti])
{
dst[v]=w+dst[lasti];
}
}
int min_i=INF,min_dst=INF;
for(int i=1;i<=n*m;i++)
{
if(!s[i])
{
if(dst[i]<min_dst)
{
min_dst=dst[i];
min_i=i;
}
}
}
if(min_i==INF)return;
lasti=min_i;
s[min_i]=1;
}
}
int main()
{
cin>>n>>m;
int now;
for(int i=1;i<=m;i++)
{
cin>>c[i];
if(c[i]==0)now=i;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=m;k++)
{
int u=convert(i,j),v=convert(i+c[k],k),w=abs(j-k)+abs(2*c[k]);
g[u].push_back(node(v,w));
}
}
}
dij(convert(1,now));
int ans=INF;
for(int i=1;i<=m;i++)
{
int r=convert(n,i);
ans=min(ans,dst[r]);
}
if(ans!=INF)
cout<<ans<<endl;
else cout<<-1<<endl;
return 0;
}
ov.
【最短路算法例题-升降梯上】-C++的更多相关文章
- Dijkstra最短路算法
Dijkstra最短路算法 --转自啊哈磊[坐在马桶上看算法]算法7:Dijkstra最短路算法 上节我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最 ...
- 10行实现最短路算法——Dijkstra
今天是算法数据结构专题的第34篇文章,我们来继续聊聊最短路算法. 在上一篇文章当中我们讲解了bellman-ford算法和spfa算法,其中spfa算法是我个人比较常用的算法,比赛当中几乎没有用过其他 ...
- 【坐在马桶上看算法】算法7:Dijkstra最短路算法
上周我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径 ...
- 【坐在马桶上看算法】算法6:只有五行的Floyd最短路算法
暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有 ...
- [Tyvj2032]升降梯上(最短路)
[Tyvj2032]升降梯上 Description 开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道.一辆停在轨道底部的电梯.和电梯内一杆控制电梯升 ...
- Floyd最短路算法
Floyd最短路算法 ----转自啊哈磊[坐在马桶上看算法]算法6:只有五行的Floyd最短路算法 暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计 ...
- Book 最短路算法
用HDU2544整理一下最近学的最短路算法 1.Dijkstra算法 原理:集合S表示已经找到最短路径的点,d[]表示当前各点到源点的距离 初始时,集合里面只有源点,当每个点u进入集合S时,用d[u] ...
- 近十年one-to-one最短路算法研究整理【转】
前言:针对单源最短路算法,目前最经典的思路即标号算法,以Dijkstra算法和Bellman-Ford算法为根本演进了各种优化技术和算法.针对复杂网络,传统的优化思路是在数据结构和双向搜索上做文章,或 ...
- 【啊哈!算法】算法7:Dijkstra最短路算法
上周我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”.例如求下图 ...
随机推荐
- MASMPlus汇编之简单窗体
.386 .model flat,stdcall option casemap:none ;include 定义 include windows.inc include gdi32.inc i ...
- DDD中的值对象如何用NHibernate进行映射
原文:DDD中的值对象如何用NHibernate进行映射 <component/>是NHibernate中一个有趣的特性,即是用来映射DDD(Data-Display-Debuger)概念 ...
- QT 那些事
一直做的是windows开发,有2个小项目想做到手机.看来看去,选择了QT.本文介绍自己的学习的一些心得,希望对你有帮助.1.选择QT2.安卓的一些事3.QML调用C++4.资源集成(比较有用,网上资 ...
- WPF使用AForge实现Webcam预览(一)
本文简略地介绍一下如果使用AForge来实现前置/后置摄像头的预览功能. 要使用AForge,就需要添加AForge NuGet相关包的引用,这些包依赖的其他包会自动安装. AForge.Contro ...
- 图形界面编程成就了C++
听有人说C#.VB比C++好是因为做界面方便还算傻得可爱,听有人说用C++做数值计算而不屑于做界面可就对不起咱C++的恩人了.这我可要说道说道. 想当年C++刚出江湖,名门出身,自立门派,想抢Obje ...
- QT---Winsocket获取网关(Gateway) 主机IP等信息
基于WinPcap库做开发,需要利用到局域网的默认网关地址和Mac地址,但是WinPcap实现获取网关IP地址没有很好的思路,可以知道的是网关的接收和发出的数据包数量一般是比局域网内的各主机要多的 ...
- Spring AOP APIS
1:Pointcut API in Spring (1):切点接口定义 org.springframework.aop.Pointcut接口是中心接口.用来将Advice(通知)定位到特定的类和方法. ...
- Android短视频中如何实现720P磨皮美颜录制?
视频中磨皮.美颜功能已成为刚需,那么如何在Android短视频中实现720P磨皮美颜录制?本篇文章中,网易云信资深开发工程师将向大家介绍具体的操作方法. 相关阅读推荐 <短视频技术详解:Andr ...
- C++程序设计2(侯捷video all)
一.转换函数Conversion function(video2) 一个类型的对象,使用转换函数可以转换为另一种类型的对象. 例如一个分数,理应该可以转换为一个double数,我们用以下转换函数来实现 ...
- kubernetes实战之consul篇及consul在windows下搭建consul简单测试环境
consul是一款服务发现中间件,1.12版本后增加servicemesh功能.consul是分布式的,可扩展的,高可用的根据官方文档介绍,目前已知最大的consul集群有5000个节点,consul ...