【最短路算法例题-升降梯上】-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最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”.例如求下图 ...
随机推荐
- Win10《芒果TV》商店版更新v3.2.0:全新播放体验,跟着爸爸,想去哪就去哪
喜迎十一月黑五大促,跟着爸爸,想去哪就去哪,<芒果TV>UWP版迅速更新v3.2.0版,全新播放页华丽蜕变,新增互动评论.猜你喜欢.宽窄屏适配.多窗体模式切换. 芒果TV UWP V3.2 ...
- 用Delphi实现文件下载的几种方法(三种使用控件的方法)
有个API就是UrlDownloadToFile.不仅如此,Delphi的一些控件也可以轻松实现下载,如NMHTTP,指定NMHTTP1.InputFileMode := ture; 指定Body为本 ...
- 浅谈网络I/O多路复用模型 select & poll & epoll
http://blog.csdn.net/nk_test/article/details/50662946
- WIN10以后如果Manifest中不写支持WIN10的话,获取版本号的API获取的是6
if TOSVersion.Major = 10 then // 高版本的Delphi(比如Berlin)可以这样写 ShowMessage('Windows 10'); 或者: if Win32M ...
- 在VS如何查看汇编代码
由于最近不常用,结果导致今天用的时候忘记了,╮(╯▽╰)╭.现在标记一下: 方法如下,先创建一个C++ Project,然后加入上面的代码,在main函数或者其他地方设置断点,注意是Debug版本,否 ...
- ViewPager页面滑动,滑动到最后一页,再往后滑动则执行一个事件
1.ViewPager在处理滑动事件的时候要用到OnPageChangeListener( 代码:this.viewPager.setOnPageChangeListener(new MyListen ...
- SQL SERVER 之快照复制,事务复制,合并复制
一.环境要求及说明 1.快照复制和事务复制是单向的(2005及以后的版本中加入了订阅端可更新的事务复制). 2.合并复制是双向的. 3.快照复制对表结构没有要求. 4.事务复制要求表有主键. 5.合并 ...
- Django多对多表的三种创建方式,MTV与MVC概念
MTV与MVC MTV模型(django): M:模型层(models.py) T:templates V:views MVC模型: M:模型层(models.py) V:视图层(views.py) ...
- C语言之父Dennis Ritchie告诉你:如何成为世界上最好的程序员?
文/Ohans Emmanuel 译/网易云信 想要阅读更多技术干货文章,欢迎关注网易云信博客. 了解网易云信,来自网易核心架构的通信与视频云服务. 我不知道如何成为世界上最好的程序员.但是,我们可以 ...
- idea初见问题整理_错误: -source 1.5 中不支持 diamond 运算符
最近在移动工程到idea下,顺便改目录结构,遇到的问题不一定全部记录,有些答案摘抄自别人博客,已注明来源,由于不是摘抄自同一作者,且有自己的一些内容,所以标注为原创. 1.(错误: -source 1 ...