链接:
1654. 到家的最少跳跃次数
题意:
从0出发,到X的最少步数
- 它可以 往前 跳恰好
a
个位置(即往右跳)。 - 它可以 往后 跳恰好
b
个位置(即往左跳)。 - 它不能 连续 往后跳
2
次。 - 它不能跳到任何
forbidden
数组中的位置。
解:
乐了,这下真成傻子了
两个判断条件我把有continue的放前面了
基本的DFS+DP,要注意一下几个点
-
分成两个数组,一个装加减都可以的,一个装只能加的,vector,unordered_set都行
-
找加减都能走的时候,条件是
dp[i+a]>=dp[i]+1
而不是dp[i+a]>dp[i]+1
,因为即使dp[i+a]==dp[i]+1
时,有可能那一步是通过某个数减到达的,那么这个数只经过了加,而我们找加减都行就要算上他 -
对于找只能加的就很好判断了
dp[i-b]>dp[i]+1
,因为这个数如果之前出现过,如果是加来的,它就经过了加减,如果是减来的,它就经过了加,总之它在这一步之前就计算过了加的结果,就不用再算了 -
上界没超过6000,这个看评论区推的,我还以为4001
-
先算只能加的那个数组更快,原理不想想了
-
贴个数据
-
vector/先加/后加减
-
vector/先加减/后加
-
unordered_set/先加/后加减
-
unordered_set/先加减/后加
实际代码:
#include<bits/stdc++.h>
using namespace std;
static constexpr int Max=1E5+7;
int minimumJumps(vector<int>& forbidden, int a, int b, int x)
{
map<int,bool>book;
for(auto i:forbidden) book[i]=true;
vector<int>dp(Max,INT_MAX-1);dp[0]=0;
vector<int>start{0},noBack;//unordered_set
while(true)
{
vector<int>next,nextNoBack;//unordered_set
//加
for(auto i:noBack)
{
if(book.find(i+a)!=book.end() || i+a>6001 || dp[i+a]<dp[i]+1) continue;
else
{
dp[i+a]=dp[i]+1;
next.push_back(i+a);
}
}
//加减
for(auto i:start)
{
if(book.find(i-b)==book.end() && i-b>=0 && dp[i-b]>dp[i]+1)
{
dp[i-b]=dp[i]+1;
nextNoBack.push_back(i-b);
}
if(book.find(i+a)!=book.end() || i+a>6001 || dp[i+a]<dp[i]+1) continue;
else
{
dp[i+a]=dp[i]+1;
next.push_back(i+a);
}
}
start=next;
noBack=nextNoBack;
if(start.empty() && noBack.empty()) break;
}
if(x==0) return 0;
return dp[x]==INT_MAX-1 ? -1 : dp[x];
}
int main()
{
vector<int> forbidden;int a,b,x,temp;
cin>>a>>b>>x;
while(cin>>temp) forbidden.push_back(temp);
int ans=minimumJumps(forbidden,a,b,x);
cout<<ans<<endl;
return 0;
}
限制:
1 <= forbidden.length <= 1000
1 <= a, b, forbidden[i] <= 2000
0 <= x <= 2000
forbidden
中所有位置互不相同。- 位置
x
不在forbidden
中。