升降梯上

开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道、一辆停在轨道底部的电梯、和电梯内一杆控制电梯升降的巨大手柄。

塔一共有 N 层,升降梯在每层都有一个停靠点。

手柄有 M 个控制槽,第 i 个控制槽旁边标着一个数 C**i,满足 C1<C2<C3<…<C M

如果 C**i>0,表示手柄扳动到该槽时,电梯将上升 C**i 层;如果 C**i<0,表示手柄扳动到该槽时,电梯将下降 −C**i 层;并且一定存在一个 C**i=0,手柄最初就位于此槽中。注意升降梯只能在 1∼N 层间移动,因此扳动到使升降梯移动到 1 层以下、N* 层以上的控制槽是不允许的。

电梯每移动一层,需要花费 2 秒钟时间,而手柄从一个控制槽扳到相邻的槽,需要花费 1 秒钟时间。

探险队员现在在 1 层,并且想尽快到达 N 层,他们想知道从 1 层到 N 层至少需要多长时间?

输入格式

第一行两个正整数 NM

第二行 M 个整数 C1、C2…C**M*。

输出格式

输出一个整数表示答案,即至少需要多长时间。

若不可能到达输出 −1。

数据范围

1≤N≤1000,2≤M≤20,−N<C1<C2<…<C**M<N

输入样例:

6 3
-1 0 2

输出样例:

19

链接

久违的一遍ac

额,-1忘记判断了,这个要是在比赛的时候吃上一发罚时可受不了

总体就是一个dp的思路,而如果用普通的dp写的话,因为停止条件的原因,会有很多的不必要的时间复杂度。
比较dijkstra本身就是dp,所以其实加维度什么的都没问题。

直接给dijkstra加维度来计算边权就可以了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
	char c=getchar();int a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
struct edge
{
	int next,to,v;
}e[200001];
int head[200001],tot;
inline void add(int i,int j,int v)
{
	e[++tot].next=head[i];
	e[tot].to=j;
	e[tot].v=v;
	head[i]=tot;
}
int n,m,dist[1001][21],vis[1001][21],c[21],s;
void dijkstra()
{
	priority_queue<pair<int,pair<int,int> > ,vector<pair<int,pair<int,int> > >,greater<pair<int,pair<int,int> > > > q;
	q.push({0,{s,1}});
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	dist[1][s]=0;
	while(!q.empty())
	{
		int x=q.top().second.second;
		int y=q.top().second.first;
		q.pop();
		if(vis[x][y]==1)continue;
		vis[x][y]=1;
		for(int i=head[x];i!=0;i=e[i].next)
		{
			int u=e[i].to;
			int v=abs(e[i].v-y)+abs(u-x)*2;
			if(dist[u][e[i].v]>dist[x][y]+v)
			{
				dist[u][e[i].v]=dist[x][y]+v;
				q.push({dist[u][e[i].v],{e[i].v,u}});
			}
		}
	}
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=m;i++)
	{
		c[i]=read();
		if(c[i]==0)s=i;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(i+c[j]>=1&&i+c[j]<=n&&c[j]!=0)add(i,i+c[j],j);
		}
	}
	dijkstra();
	int ans=0x3f3f3f3f;
	for(int i=1;i<=m;i++)
	{
		ans=min(ans,dist[n][i]);
	}
	if(ans!=1061109567)
	cout<<ans<<endl;
	else 
	cout<<-1<<endl;
	return 0;
}

没啥好说的。
感觉上一题学到的更多

posted @ 2024-03-13 15:27  HL_ZZP  阅读(5)  评论(0编辑  收藏  举报